docs: CLAUDE.md 语言设计哲学增加L化适配原则

This commit is contained in:
2026-06-05 19:07:54 +08:00
parent 6bd6eaae47
commit 095604dc9f
+75 -36
View File
@@ -6,62 +6,101 @@ L Language v0.5 — 用 C17 实现的静态类型编译型编程语言,Rust
## 语言设计哲学 ## 语言设计哲学
L 借鉴 Rust 语法骨架(let/mut/struct/impl/match),但有自己的设计理念: L 借鉴 Rust 语法骨架(let/mut/fn/struct/impl/match),但有自己的设计理念:
1. **去糖优先** — 复杂语法在 parser 层去糖为简单原语,零 sema/codegen 改动。已验证: for/match/复合赋值。 1. **去糖优先** — 复杂语法在 parser 层去糖为简单原语,零 sema/codegen 改动。已验证: for/match/复合赋值。
2. **博采众长** — 从多语言吸收优秀特性,而非单一模仿 Rust: 2. **博采众长L 化适配** — 从多语言吸收优秀特性,但必须适配 L 的语法风格,**不能直接照抄**。每条特性要问:这个特性的核心价值是什么?在 L 里最自然的表达方式是什么?
- **Elixir/F#** → 管道运算符 `|>`
- **Go** → defer、多返回值
- **Swift** → guard、字符串插值、命名参数
- **Kotlin** → 扩展函数、when 表达式
- **Python** → 列表推导式、装饰器
- **Zig** → comptime 常量折叠
3. **渐进演进** — 先加语法糖(parser 层),后加强类型(sema/codegen 层) 3. **渐进演进** — 先加语法糖(parser 层),后加强类型(sema/codegen 层)
### L 化适配原则
从其他语言借鉴特性时,必须按 L 的风格加以改造:
| 规则 | 说明 | 反例(直接照抄) | 正例(L 化后) |
|------|------|-----------------|---------------|
| **花括号块** | 所有代码块用 `{}`,不引入缩进块 | Python `for x in arr:` + 缩进 | `for x in arr { ... }` |
| **类型后置** | 类型标注用 `name: Type`,不用前置类型 | C `int x`、Go `func f() int` | `let x: i64``fn f() -> i64` |
| **snake_case** | 函数/变量用 snake_case,类型用 PascalCase | `drawRect()``MAX_SIZE` | `draw_rect()`、类型 `MaxSize`(但常量仍 `MAX_SIZE` |
| **显式 return** | 返回值必须写 `return`,不用隐式尾表达式 | Rust `fn f() -> i64 { 42 }` | `fn f() -> i64 { return 42; }` |
| **关键字优先** | 新特性优先用关键字,不引入符号噪音 | `x?.y`(空安全链) | 暂不引入,等类型系统成熟后用 `?` 也可接受 |
| **保持对称** | 开闭符号成对,不用 `end`/`done` 等结尾词 | Ruby `if ... end` | `if ... { }` |
| **语义透明** | 语法糖的去糖结果必须可预测,文档里写清楚 | 隐藏的隐式转换 | 每个 sugar 标注 `// 去糖为: ...` |
| **一致缩写** | 关键字缩写风格统一,不混用缩写与全称 | `func` + `def` + `fn` 混用 | 全部用短关键字: `fn`/`let`/`mut` |
### 各语言特性借鉴分析
分析每种语言时,区分"核心思想"和"表面语法",取其思想、适配语法:
| 来源语言 | 特性 | 核心思想 | L 化语法 | 适配要点 |
|----------|------|---------|---------|---------|
| **Elixir/F#** | 管道 | 数据从左到右流经函数 | `10 \|> double() \|> add(5)` | 保持 `()` 调用、不用空格传参 |
| **Swift** | guard | 提前返回(早退模式) | `guard x >= 0 else { return -1; }` | 保留 `else` 关键字 + 花括号块 |
| **Swift** | 字符串插值 | 表达式嵌入字符串 | `"Hello, \\(name)!"` | 用 `\\(...)` 而非 `{...}`,避免与块语法冲突 |
| **Swift/Kotlin** | 命名参数 | 调用点标注参数名 | `draw_rect(width: 10, height: 20)` | 用 `:` 分隔(与类型标注一致) |
| **Python** | 列表推导式 | 声明式生成列表 | `[for x in arr if x > 0: x * 2]` | 用 L 的 `for-in` 语法,不用 Python 后缀式 |
| **Python** | 装饰器 | 函数/类型的元编程包装 | 慎用 `@` 符号,考虑用 `#[attr]`(Rust 风格更搭 L | 语法需与 attribute 体系统一设计 |
| **Go** | defer | 作用域退出时执行 | `defer cleanup();` | 关键字 + 常规调用语法 |
| **Go** | 多返回值 | 函数返回多个值 | `fn div(a: i64, b: i64) -> (i64, i64)` | 用元组括号,不用 Go 的裸逗号 |
| **Zig** | comptime | 编译期求值 | `const x = comptime 1 + 2;` | `const` 表明编译期常量 |
| **Kotlin** | 扩展函数 | 为已有类型添加方法 | `impl str { fn is_email(self: str) -> bool { ... } }` | 复用 `impl` 块,不用 `Type.method` 语法 |
| **Kotlin** | when 表达式 | 多分支条件 + 返回值 | 已有 `match`,将 match 升级为表达式 | 不用新关键字,扩展现有语法 |
| **Carbon/Cpp2** | in/out 参数 | 明确参数传递方向 | `fn f(in x: i64, out y: i64)` | 复用类型标注位置,前缀修饰 |
### 候选特性优先级 ### 候选特性优先级
| 优先级 | 特性 | 来源 | 实现层 | 预计行数 | 独特性 | | 优先级 | 特性 | 来源 | 实现层 | 预计行数 | L 化关键 |
|--------|------|------|--------|---------|--------| |--------|------|------|--------|---------|---------|
| **P0** | 管道 `\|>` | Elixir/F# | parser | ~30 | 极高 | | **P0** | 管道 `\|>` | Elixir/F# | parser | ~30 | 保持 `()` 调用风格 |
| **P0** | guard 语句 | Swift | parser | ~15 | | | **P0** | guard 语句 | Swift | parser | ~15 | `else` + 花括号块 |
| **P0** | 字符串插值 | Swift/Python | lexer+parser | ~60 | | | **P0** | 字符串插值 | Swift | lexer+parser | ~60 | `\\(expr)` 避免 `{}` 歧义 |
| **P0** | 命名参数 | Swift/Kotlin | parser | ~50 | | | **P0** | 命名参数 | Swift | parser | ~50 | `name: val` 与类型标注统一 |
| P1 | 列表推导式 | Python | parser | ~50 | | | P1 | 列表推导式 | Python | parser | ~50 | `[for x in arr if cond: expr]`,不用 Python 后缀式 |
| P1 | 装饰器 `@` | Python | parser | ~40 | | | P1 | 装饰器 | Python | parser | ~40 | 考虑 `#[attr]` 而非裸 `@` |
| P1 | defer | Go/Zig | parser+codegen | ~60 | | | P1 | defer | Go | parser+codegen | ~60 | 关键字 + 花括号/单语句 |
| P1 | 扩展函数 | Kotlin | parser+sema | ~80 | | | P1 | 扩展函数 | Kotlin | parser+sema | ~80 | 复用 `impl` 块,不造新语法 |
| P1 | when 表达式 | Kotlin | parser | ~30 | | | P1 | match 表达式 | Kotlin | parser | ~30 | 扩展现有 match,不引入 `when` |
| P2 | 多返回值 | Go | 全流水线 | ~200 | | | P2 | 多返回值 | Go | 全流水线 | ~200 | `(T, U)` 元组语法,不用裸逗号 |
| P2 | 空安全 `?.` / `??` | Kotlin | sema+codegen | ~150 | | | P2 | 空安全 `?.` / `??` | Kotlin | sema+codegen | ~150 | 保留符号运算符(符号在此场景比关键字更清晰) |
| P2 | comptime 求值 | Zig | sema+codegen | ~200 | 极高 | | P2 | comptime 求值 | Zig | sema+codegen | ~200 | `comptime` 作为表达式前缀 |
| P3 | 隐式接口 | Go | sema+codegen | ~300 | | | P3 | 隐式接口 | Go | sema+codegen | ~300 | 暂远,与 trait 体系统一设计 |
| P3 | in/out 参数 | Carbon/Cpp2 | sema+codegen | ~150 | | | P3 | in/out 参数 | Carbon/Cpp2 | sema+codegen | ~150 | 前缀修饰符,放在 `name: Type` 之前 |
### P0 特性设计 ### P0 特性设计L 化版)
**管道 `|>`** — 数据流从左到右: **管道 `|>`** — 数据流从左到右,保持 `()` 调用:
```rust ```rust
let result = 10 |> double() |> add(5); let result = 10 |> double() |> add(5);
// 糖为: add(double(10), 5) // 糖为: add(double(10), 5)
// 注意: RHS 必须是函数调用形式(带括号),不支持 `10 |> double`(与 Elixir 不同)
// 管道优先级低于所有运算符: a + b |> f() → f(a + b)
``` ```
**guard** — 提前返回的语法糖: **guard** — 提前返回,保留 `else` 关键字 + 花括号:
```rust ```rust
guard x >= 0 else { return -1; } guard x >= 0 else { return -1; }
// 糖为: if !(x >= 0) { return -1; } // 糖为: if !(x >= 0) { return -1; }
// guard 块内只允许 return/continue/break 等跳转语句
// else 块必须用花括号,即使只有一条语句
``` ```
**字符串插值**: **字符串插值** — 用 `\(expr)` 而非 `{expr}`,避免与块语法冲突:
```rust ```rust
let msg = "Hello, {name}! Age: {age}"; let name = "World";
// 脱糖为: "Hello, " + name + "! Age: " + age let msg = "Hello, \(name)!";
// 去糖为: "Hello, " + name + "!"
// 转义: 字面量 \( 写作 \\\(,字面量 \ 写作 \\
// 与 Swift 的区别: Swift 用 \(),L 也采用此方案因为与 C 转义字符 \n \t 视觉一致
``` ```
**命名参数**调用点可选标注: **命名参数**`name: value` 与类型标注 `name: Type` 视觉统一:
```rust ```rust
fn drawRect(width: i64, height: i64) { ... } fn draw_rect(width: i64, height: i64) -> void { ... }
drawRect(width: 10, height: 20); // 命名
drawRect(10, 20); // 位置 draw_rect(width: 10, height: 20); // 命名调用
draw_rect(10, 20); // 位置调用(等价)
// 命名参数与位置参数可混用: draw_rect(10, height: 20)
// 命名参数必须放在位置参数之后
// 与 Swift 的区别: 不需要外部/内部参数名区分,参数名即标签名
``` ```
## 构建命令 ## 构建命令