# Uya 语言正式语法规范（Formal BNF）

> **版本**：与 [uya.md](./uya.md) 0.49.56 同步（2026-10-23）

本文档包含 Uya 语言的完整、无歧义的 BNF 语法定义，用于：
- 编译器/解析器实现
- 语言标准化参考
- 语法形式化验证

> **注意**：本文档是 [uya.md](./uya.md) 的补充，详细语法说明请参考主文档。  
> 对于日常开发和快速参考，请使用 [grammar_quick.md](./grammar_quick.md)。

---

## 完整语法汇总

### 程序结构

```
program        = { declaration }
declaration    = fn_decl | struct_decl | struct_method_block | union_decl | union_method_block
               | interface_decl | enum_decl | type_alias_decl | const_decl | var_decl
               | error_decl | extern_decl | import_stmt | test_stmt
               | macro_decl | c_import_decl | cfg_decl

# 顶层前缀顺序固定（src/parser/main.uya:710-928）：
#   'export' → 'opaque'（仅 struct） → '@align(N)' → '@async_fn' | '@naked_fn' → 声明关键字
# 例：export opaque struct S { ... }、@align(64) @async_fn fn f() Future<!i32> { ... }
# 反序写法（如 'extern export fn'、'@async_fn @align(64) fn'）是语法错误

type_alias_decl = 'type' ID '=' type ';'
var_decl       = ('const' | 'var') ID ':' type '=' expr ';'
c_import_decl  = '@c_import' '(' STRING [ ',' STRING [ ',' STRING ] ] ')' ';'
cfg_decl       = 'std' '.' 'cfg' '(' cfg_cond ',' cfg_decl_arg [ ',' cfg_decl_arg ] ')'
cfg_cond       = 'std' '.' ('host_os' | 'host_arch' | 'target_os' | 'target_arch') ('==' | '!=') '.' ID
cfg_decl_arg   = '{' { declaration } '}' | declaration
```

**说明**：
- `type_alias_decl`：类型别名，见[类型别名声明](#类型别名声明)
- `c_import_decl`：顶层构建指令，把外部 C 源纳入当前构建图；1–3 个实参只能是字符串字面量（路径、`cflags`、`ldflags`），声明末尾必须有 `;`（`src/parser/declarations.uya:18-94`）。它不是表达式，不能写在表达式位置或函数体内
- `cfg_decl`：编译期平台裁剪，条件仅支持 `std.host_os` / `std.host_arch` / `std.target_os` / `std.target_arch` 配合 `==` / `!=`；`then` / `else` 分支各是一个声明块或单条声明，`else` 分支可省略（`src/parser/main.uya:403-620`）
- 顶层 `const` / `var` 与函数体内的变量声明共用同一条产生式 `var_decl`

### 函数声明

```
fn_attr        = fn_align_attr | async_fn_attr | naked_fn_attr
fn_align_attr  = '@align' '(' NUM ')'    # 函数帧对齐；仅对 @async_fn 生成的帧结构体生效（src/ast.uya:233）
async_fn_attr  = '@async_fn'
naked_fn_attr  = '@naked_fn'
fn_decl        = [ 'export' ] [ fn_attr ] [ 'extern' [ STRING ] ] 'fn' ID [ '<' type_param_list '>' ] '(' [ param_list ] [ '...' ] ')' type ( '{' statements '}' | ';' )
param_list     = param { ',' param }
param          = ID ':' type
type_param_list = type_param { ',' type_param }
type_param     = ID [ ':' constraint_list ]
constraint_list = ID { '+' ID }
```

**属性与参数**：
- **属性写法**（`src/parser/main.uya:744-793`）：`@align(N)` 必须写在 `@async_fn` 之前；`@async_fn` 之后必须紧跟 `fn`；`@naked_fn` 与 `@async_fn` 不能用于 `extern` 函数。`@align` 的 `N` 是整数字面量（`@align` 是声明属性，不是表达式内置函数，见[内联汇编](#内联汇编)说明）
- **`;` 形式的函数体**只属于 `extern` 声明；普通 `fn` 必须有函数体（`src/parser/declarations.uya:2125-2135`）
- **变参**：参数列表末尾可写一个 `...`（`fn sum(...) i32`、`fn f(fmt: *byte, ...) void`），由 `@params` / `@va_start` 等内置访问（`src/parser/declarations.uya:2018-2028`）；参数没有默认值语法
- **`export` 必须写在 `extern` 之前**：`export extern fn` 合法，`extern export fn` 是语法错误

**说明**：
- **函数可见性**（0.43 新增 `extern "libc"`）：
  - `fn name(...) type { ... }`：内部函数，生成的 C 代码添加 `static`
  - `export fn name(...) type { ... }`：导出函数，生成的 C 代码不添加 `static`，带 `uya_` 前缀
  - `extern fn name(...) type;`：外部 C 函数声明（无函数体，分号结尾）
  - `extern fn name(...) type { ... }`：Uya 实现的 C 兼容函数，生成的 C 代码为 `void foo(void) { ... }`（不带 `uya_` 前缀）
  - `export extern fn name(...) type;`（无函数体）：不生成代码，链接到 C 标准库
  - `export extern fn name(...) type { ... }`（有函数体）：Uya 实现，生成的 C 代码为 `void foo(void) { ... }`（不带 `uya_` 前缀）
  - **`extern "libc" fn`**（0.43 新增）：显式声明 C 标准库函数，`byte` 映射为 `char`
- **泛型函数语法**：`fn max<T: Ord>(a: T, b: T) T { ... }`
- 类型参数列表可选，使用尖括号 `<T>` 或 `<T: Constraint>`
- 多约束使用 `+` 连接：`<T: Ord + Clone + Default>`

### 结构体声明

```
struct_decl    = [ 'opaque' ] 'struct' ID [ '<' type_param_list '>' ] [ ':' interface_list ] '{' struct_body '}'
interface_list = ID { ',' ID }
struct_body    = ( field_list | method_list | field_list method_list )
field_list     = field { ',' field }
field          = ID ':' type
method_list    = method_decl { method_decl }
method_decl    = [ async_fn_attr ] 'fn' ID [ '<' type_param_list '>' ] '(' [ param_list ] ')' type '{' statements '}'  # 若首参类型为 &Self / &StructName（联合体为 &UnionName），则视为实例方法；否则为静态方法；特例：drop 必须为 fn drop(self: T) void

**补充规则**：
- `drop` 只能在结构体 / 联合体内部或对应方法块中声明为 `fn drop(self: T) void { ... }`。
- `drop` 不是用户可显式调用的普通函数；`drop(x)`、`T.drop(x)`、`x.drop()` 都是编译错误。

# 结构体外部方法定义（方式2）
struct_method_block = ID '{' method_list '}'
type_param_list = type_param { ',' type_param }
type_param     = ID [ ':' constraint_list ]
constraint_list = ID { '+' ID }
```

**说明**：
- **`opaque struct`**（`src/parser/main.uya:744-753`、`src/checker/check_expr.uya:3666`、`src/checker/check_expr_extra.uya:398`）：`opaque` 只是 `struct` 的声明属性，必须紧邻 `struct`（`opaque fn` 等写法是语法错误）；声明模块外**不能构造**该结构体字面量、也**不能访问其字段**。导出写法：`export opaque struct Name { ... }`
- **接口声明**：结构体定义时可以声明实现的接口，语法为 `struct StructName : InterfaceName1, InterfaceName2 { ... }`
  - 接口声明是可选的，如果结构体不实现接口，可以不声明
  - 接口方法作为结构体方法定义，可以在结构体内部或外部方法块中定义
- **方式1：结构体内部定义**：方法定义在结构体花括号内，与字段定义并列
  - 语法：`struct StructName : InterfaceName { field: Type, fn method(self: &Self) ReturnType { ... } }`
- **方式2：结构体外部定义**：使用块语法在结构体定义后添加方法
  - 语法：`StructName { fn method(self: &Self) ReturnType { ... } }`
- 方法实现允许使用可选前缀 `@async_fn`
- 实例方法按**第一个参数的类型**判定：
  - 结构体：`&Self` 或 `&StructName`
  - 联合体：`&Self` 或 `&UnionName`
- 参数名不限；`self` 只是惯例，不是语义判定条件
- 所有方法都允许以 `Type.method(...)` 形式调用；当首参为实例 receiver 时，额外允许 `obj.method(...)` 语法糖
- 方法调用可继续参与任意深度的后缀链；例如 `obj.method().next().field`、`obj.method<T>().next()`
- 推荐使用 `Self` 占位符：`self: &Self` 更简洁
- 详细语法说明见 [uya.md](./uya.md#29-扩展特性) 结构体方法部分

### 接口声明

```
interface_decl = 'interface' ID [ '<' type_param_list '>' ] '{' (method_sig | interface_name)+ '}'  # 方法签名或组合接口名
method_sig     = [ async_fn_attr ] 'fn' ID '(' [ param_list ] ')' type ';'
interface_name = ID ';'  # 组合接口名，用分号分隔
type_param_list = type_param { ',' type_param }
type_param     = ID [ ':' constraint_list ]
constraint_list = ID { '+' ID }
```

**说明**：
- `method_sig+` 表示一个或多个方法签名（BNF 扩展语法，等价于 `method_sig { method_sig }`）
- `interface_name` 表示接口组合，在接口体中直接列出被组合的接口名，用分号分隔
- 接口必须至少包含一个方法签名或组合接口名
- 接口实现：结构体在定义时声明接口（`struct StructName : InterfaceName { ... }`），接口方法作为结构体方法定义
- 接口方法签名允许使用可选前缀 `@async_fn`；对接口而言，异步 ABI 仍由返回 `Future<!T>` / `!Future<T>` 表达
- 详细语法说明见 [uya.md](./uya.md#6-接口interface)

### 联合体声明

```
union_decl     = 'union' ID [ ':' interface_list ] '{' union_body '}'
union_body     = ( field_list | method_list | field_list method_list )
union_method_block = ID '{' method_list '}'  # 联合体外部方法定义（同结构体方式2）
```

**说明**：
- 联合体语法与结构体类似，但所有变体共享同一内存区域
- 变体命名遵循标识符规则，创建语法：`UnionName.variant(expr)`
- 访问必须通过模式匹配（`match`）或编译器可证明的已知标签直接访问
- 详细语法说明见 [uya.md](./uya.md#45-联合体union)

### 枚举声明

```
enum_decl      = 'enum' ID '{' enum_variant_list '}'
enum_variant_list = enum_variant { ',' enum_variant }
enum_variant   = ID [ '=' NUM ]  # 枚举变体，可选显式赋值
```

**说明**：
- 枚举声明在顶层（与函数、结构体定义同级）
- 底层类型固定为 `i32`；**没有** `enum E : i32 { ... }` 这种底层类型注解语法 ——
  实测 `enum Color : i32 { ... }` 报 `意外的 token ':'`。此前本节写有
  `[ ':' underlying_type ]` 产生式，与实现脱节，已删除。
- 枚举变体可以显式指定值（使用 `=` 后跟整数常量），实测生效：
  `enum Color { RED = 5, GREEN = 5 }` 两个变体相等。
- 枚举值在编译期确定，类型安全
- 详细语法说明见 [uya.md](./uya.md#2-类型系统) 枚举类型部分

### 类型别名声明

```
type_alias_decl = 'type' ID '=' type ';'
```

**说明**：
- 顶层声明，`type` 后必须是标识符（`@asm_reg` 一类内置类型名不能作为别名名），`=` 后是任意 `type` 产生式，末尾必须有 `;`（`src/parser/declarations.uya:1357-1406`）
- 可导出：`export type MyInt = i64;`
- 示例：`type ComparFunc = fn(*void, *void) i32;`、`type Vec4f32 = @vector(f32, 4);`

### 类型系统

```
type           = base_type | pointer_type | array_type | slice_type 
               | struct_type | union_type | interface_type | enum_type | tuple_type
               | atomic_type | error_union_type | function_pointer_type | extern_type
               | vector_type | mask_type | frame_type

base_type      = 'i8' | 'i16' | 'i32' | 'i64' | 'u8' | 'u16' | 'u32' | 'u64'
               | 'f32' | 'f64' | 'bool' | 'byte' | 'void' | 'usize'
pointer_type   = '&' [ 'const' ] type | '*' [ 'const' ] type  # 0.42 新增 &const T 和 *const T
array_type     = '[' type ':' NUM ']'
slice_type     = '&[' [ 'const' ] type ']' | '&[' [ 'const' ] type ':' expr ']'  # 0.49.43：元素只读 & [ const T ]（如 &[const byte]）；带长度形参写法用 ': N'（如 &[i32: 3]）
struct_type    = ID [ '<' type_arg_list '>' ]
union_type     = ID [ '<' type_arg_list '>' ] | 'union' ID  # 联合体类型；'union' ID 用于外部 C 联合体
interface_type = ID [ '<' type_arg_list '>' ]
type_arg_list  = type { ',' type }
enum_type      = ID  # 枚举类型，通过枚举声明定义
tuple_type     = '(' type { ',' type } ')'  # 元组类型，如 (i32, f64)
atomic_type    = 'atomic' type
error_union_type = '!' type  # 错误联合类型，表示 T | Error
function_pointer_type = 'fn' '(' [ param_type_list ] ')' type  # 函数指针类型
param_type_list = type { ',' type }  # 函数指针类型的参数类型列表（无参数名）
vector_type    = '@vector' '(' type ',' NUM ')'
mask_type      = '@mask' '(' NUM ')'
frame_type     = '@frame' '(' ID [ '<' type_arg_list '>' ] ')'
```

**说明**：
- **`&[const T]`**（**0.49.43**）：切片元素只读；字符串字面量赋给切片类型时须为 **`&[const byte]`**（或带长度形参的 **`&[const byte: N]`**），见 uya.md 规范变更 0.49.43
- `@vector(T, N)` 表示元素类型为 `T`、通道数为 `N` 的向量类型
- `@mask(N)` 表示 `N` 通道的掩码类型
- `@frame(fn_name)` 或 `@frame(fn_name<T>)` 表示 async 函数 `fn_name` 的状态机帧类型
- 第一阶段 `N` 仅允许字面量正整数
- 第一阶段 `N` 必须为 2 的幂，建议限制为 `2`、`4`、`8`、`16`、`32`、`64`
- `vector_type` 在语法层允许任意 `type` 作为第一个参数；语义层会进一步限制 `T` 必须为数值标量类型
- `@frame` 的语义层要求 `fn_name` 必须是 `@async_fn`；若带泛型参数，则必须为 concrete 类型
- 第一阶段不引入 `@vector<T>(N)`、`Vector(T, N)`、通用 const generics 或新的目标特性查询语法

### 变量声明

```
var_decl       = ('const' | 'var') ID ':' type '=' expr ';'
const_decl     = 'const' ID ':' type '=' expr ';'
destructure_decl = ('const' | 'var') '(' ID { ',' ID } ')' '=' expr ';'
```

**说明**：
- 初始化器默认必需；唯一例外是 `@frame(...)` 类型的声明可以省略 `=`（由声明点分配/零初始化，`src/parser/statements.uya:553-575`）
- `destructure_decl`：元组解构，`const (x, y) = point;`、`const (x, _, z) = get_tuple();`（`_` 表示忽略该位）
- 声明中的绑定名可以是 `type` 这个关键字（编译器内部用于宏展开）

### 语句

```
statements     = { statement }        # 语句序列，可为空；函数体/块/分支体都用它
statement      = expr_stmt | var_decl | destructure_decl | return_stmt | if_stmt | while_stmt
               | for_stmt | break_stmt | continue_stmt | defer_stmt | errdefer_stmt
               | block_stmt | match_stmt | test_stmt

expr_stmt      = expr ';'
return_stmt    = 'return' [ expr ] ';'
if_stmt        = 'if' expr ( '{' statements '}' | statement ) [ 'else' ( if_stmt | '{' statements '}' | statement ) ]
while_stmt     = 'while' expr '{' statements '}'
for_stmt       = 'for' iterable '|' ID '|' '{' statements '}'        # 值迭代（只读）
               | 'for' iterable '|' '&' ID '|' '{' statements '}'    # 引用迭代（可修改）
               | 'for' range [ '|' [ '&' ] ID '|' ] '{' statements '}'  # 整数范围，绑定变量可省略
iterable       = expr
range          = expr '..' [ expr ]

# 详细说明：
# - iterable：可迭代对象；此形式必须有 |ID| 或 |&ID| 绑定，省略绑定（'for obj { ... }'）
#   是语法错误（src/parser/statements.uya:357-434）。当前检查器只接受定长数组与
#   实现了 next() 迭代器接口的具体类型（切片不在其中，见 src/checker/check_node_extra.uya:560-660）
# - range：整数范围表达式，如 0..10 或 0..（无限范围）；省略变量绑定表示只循环次数
# - |ID|：值迭代（只读），绑定元素值
# - |&ID|：引用迭代（可修改），绑定元素指针
# 详细语法说明见 [uya.md](./uya.md#8-控制流)
break_stmt     = 'break' ';'
continue_stmt  = 'continue' ';'
defer_stmt     = 'defer' ( statement | '{' statements '}' )
errdefer_stmt  = 'errdefer' ( statement | '{' statements '}' )

# defer/errdefer 块内禁止：return、break、continue、@await
# 允许：表达式、赋值、函数调用、语句块
# 替代方案：使用变量记录状态，在 defer/errdefer 外处理控制流
block_stmt     = '{' statements '}'
match_stmt     = match_expr
match_expr     = 'match' expr '{' pattern_list '}'
test_stmt      = 'test' STRING '{' statements '}'
```

### 表达式

```
expr           = assign_expr
assign_expr    = pipeline_expr [ ('=' | '+=' | '-=' | '*=' | '/=' | '%=') assign_expr ]  # 右结合
pipeline_expr  = or_expr { '|>' postfix_expr }  # 左结合；优先级介于 '||' 与赋值之间
or_expr        = bitor_expr { '||' bitor_expr }
bitor_expr     = xor_expr { '|' xor_expr }
xor_expr       = and_expr { '^' and_expr }
and_expr       = bitand_expr { '&&' bitand_expr }
bitand_expr    = eq_expr { '&' eq_expr }
eq_expr        = rel_expr { ('==' | '!=') rel_expr }
rel_expr       = shift_expr { ('<' | '>' | '<=' | '>=') shift_expr }
shift_expr     = add_expr { ('<<' | '>>') add_expr }
add_expr       = mul_expr { ('+' | '-' | '+|' | '-|' | '+%' | '-%') mul_expr }
mul_expr       = cast_expr { ('*' | '/' | '%' | '*|' | '*%') cast_expr }
cast_expr      = unary_expr [ ('as' | 'as!') type ] { catch_op }  # 'as' 比一元运算更外层：-x as i64 即 (-x) as i64
unary_expr     = 'try' rel_expr                                  # try 的操作数按相对表达式解析（try a + b 即 try (a + b)）；操作数须提供 !T：错误联合值，或整数算术表达式（checked：溢出→error.Overflow，除零→error.DivisionByZero）
               | ('!' | '-' | '~' | '&' | '*') unary_expr         # 右结合
               | postfix_expr
postfix_expr   = primary_expr { '.' (ID | NUM) | '[' expr ']' | '(' arg_list ')' | slice_op }
                # '.' NUM 用于元组字段访问，如 tuple.0, tuple.1
                # 花括号字面量、括号表达式、下标结果、方法调用结果都可继续重复接同一套后缀，因此链式调用深度不受限制
                # 泛型方法调用在解析歧义消解后同样归入这条后缀链，如 obj.method<T>().next()
                # 0.49.41：STRING 为 primary_expr 时，可接 '[' expr ']'（下标）或 slice_op（与数组字面量、标识符一致），如 "hello"[0:3]、&"hello"[0:3]
catch_op       = 'catch' [ '|' ID '|' ] '{' statements '}'      # 后缀，可连续多个（左结合），见 src/parser/expressions.uya:63-138；是 cast 级后缀，就地处理整条算术须写 (a + b) catch {}

**类型化管道 `|>` 的语义约束**（`src/checker/check_expr_extra.uya:793-870`）：

- 左侧类型必须是规范类型 `Pipeline`（`lib/std/process.uya:2609` 的 `export opaque struct Pipeline`）或 `!Pipeline`；否则报「管道运算符 '|>' 的左侧必须是 Pipeline 或 !Pipeline 类型」
- 右侧必须是最外层为调用表达式的 `postfix_expr`；且该调用**不能**是带隐式 `self` receiver 的实例方法调用，被调用函数**首个参数**类型必须是 `Pipeline`
- 左侧为 `!Pipeline` 时走 try-forward：等价于 `f(try lhs, args...)`，整体类型为 `!R`，且只能出现在返回错误联合类型的函数（或返回 `Future<!T>` 的 `@async_fn`）中
- `Pipeline` 是 move-only：同一条链只对最左侧变量做一次消费标记，链尾 sink 之后再接 `|>` 是错误

### SIMD 语义规则（第一阶段）

- `@vector(T, N)` 与 `@vector(U, M)` 仅当 `T == U` 且 `N == M` 时类型相等
- `@mask(N)` 与 `@mask(M)` 仅当 `N == M` 时类型相等
- `@mask(N)` 不隐式转换为 `bool`
- `@vector(T, N)` 不与标量类型隐式互转
- 算术运算 `+`、`-`、`*`、`/` 可用于相同类型的 `@vector(T, N)`，结果类型保持不变；`%` 仅可用于**整数元素**的相同类型 `@vector(T, N)`，按通道取模，结果类型保持不变；饱和运算 `+|`、`-|`、`*|` 仅可用于**有符号整数元素**的相同类型 `@vector(T, N)`；包装运算 `+%`、`-%`、`*%` 可用于**整数元素**的相同类型 `@vector(T, N)`（按通道，语义与标量一致）
- 位运算 `&`、`|`、`^`、`<<`、`>>` 与一元 `~` 仅适用于整数元素类型的 `@vector(T, N)`；一元 `-` 适用于整数或浮点元素类型的 `@vector(T, N)`
- 比较运算 `==`、`!=`、`<`、`<=`、`>`、`>=` 可用于相同类型的 `@vector(T, N)`，结果类型为 `@mask(N)`
- 掩码运算 `&`、`|`、`^`、`!` 可用于 `@mask(N)`
- `@vector.splat(x)` 通过上下文目标类型构造向量值；参数类型须与元素类型 `T` 一致或可隐式转换；无后缀浮点字面量为 `f64`，`f32` 向量须使用 `f32` 后缀（如 `1.0f32`）；目标类型还可由同一代数/比较/取模/饱和/包装表达式中另一侧的 `@vector` 操作数推断
- **`@vector.load(ptr)`**（**0.49.33**）：**`ptr`** 为 **`&T`**，与目标 **`@vector(T,N)`** 的元素类型匹配（**`byte`/`u8`** 互通规则同实现）；从 **`ptr`** 按向量大小装入向量值；目标类型上下文与 **`@vector.splat`** 相同；**不检查**缓冲区剩余长度
- **`@vector.store(ptr, v)`**（**0.49.34**）：**`v`** 为 **`@vector(T,N)`**，**`ptr`** 为 **`&T`** 且与 **`v`** 元素类型匹配（**`byte`/`u8`** 规则同 **`load`**）；将 **`v`** 按向量大小写入 **`ptr`**；**`void`**；**不检查**可写范围长度
- **`@vector.select(m, a, b)`**（**0.49.35**）：**`m`** 为 **`@mask(N)`**，**`a`**、**`b`** 为相同 **`@vector(T,N)`** 且 **`N`** 与 **`m`** 一致；通道 **`i`** 上 **`m`** 为真取 **`a`** 的分量，否则取 **`b`** 的分量；结果为 **`@vector(T,N)`**；目标类型上下文同 **`@vector.splat`** / **`load`**
- **`@vector.reduce_add(v)`**（**0.49.36**）：**`v`** 为 **`@vector(T,N)`**，元素类型 **`T`** 为 **`i8`–`i64`、`u8`–`u64`、`f32`、`f64`**；结果为标量 **`T`**，为各通道之和（**`+`** 语义同标量）
- **`@vector.reduce_mul(v)`**（**0.49.38**）：**`v`** 为 **`@vector(T,N)`**，元素类型 **`T`** 为 **`i8`–`i64`、`u8`–`u64`、`f32`、`f64`**；结果为标量 **`T`**，为各通道之积（**`*`** 语义同标量）
- **`@vector.reduce_min(v)`** / **`@vector.reduce_max(v)`**（**0.49.39**）：**`v`** 为 **`@vector(T,N)`**，元素类型 **`T`** 为 **`i8`–`i64`、`u8`–`u64`、`f32`、`f64`**；结果为标量 **`T`**，分别为各通道最小值 / 最大值
- `@vector.any(m)` 与 `@vector.all(m)` 接受 `@mask(N)` 并返回 `bool`
- 第一阶段不允许把 `@mask(N)` 直接作为 `if` / `while` 条件
- 第一阶段不引入 **`shuffle`**

### 内联汇编

```
asm_stmt       = '@asm' '{' { asm_instruction } '}' [ 'clobbers' '=' '[' STRING { ',' STRING } ']' ] [ ';' ]
asm_instruction = STRING '(' [ expr_list ] [ '->' expr_list ] ')' [ ';' ]
```

**说明**：
- **@asm 块**：内联汇编语句块，包含一条或多条汇编指令（至少一条）
- **指令模板**：字符串字面量，**按原样发射**；操作数用 GCC 位置编号 `%0` / `%1`（**输出在前、输入在后**）与 `%%reg`。`{name}` 占位符**未实现**，写进模板不会被替换（BNF 不变，属语义层限制）
- **输入列表**：指令的输入操作数（普通表达式），多个用逗号分隔
- **输出列表**：指令的输出操作数，使用 `->` 分隔
- **clobbers 声明**：显式声明被修改的寄存器列表，**只有块级写法**（写在 `}` 之后）；不存在逐指令 clobbers（`src/parser/primary.uya:1304-1361`）
- **内存修改**：使用 `"memory"` 字符串声明内存被修改

**示例**：
```uya
// 单条指令（输入输出都是普通表达式；输出变量须在块外先声明并初始化）
@asm {
    "add {a}, {b}" (a, b, -> result);
}

// 没有操作数的指令写 ()
@asm {
    "mov rax, 1" ();
    "nop" ();
} clobbers = ["rax"];
```

**实现约束**：
- `_` 不能作为输出操作数（会被判为 void 输出），无输出时只写输入或 `()`
- 以 `"lock "` 开头的模板要求 memory clobber，而 `"memory"` 当前只写入 `asm_clobbers_memory`、不进入 clobber 列表（`src/parser/primary.uya:1331`、`src/checker/check_expr.uya:4007-4023`）

**寄存器类型 / 内存操作类型**（内置类型名，不是普通声明，也不是 `@` 函数）：

```
@asm_reg            编译器自动分配的通用寄存器
@asm_reg_x64        x86-64 通用寄存器
@asm_reg_x64_xmm    x86-64 SSE（128 位）
@asm_reg_x64_ymm    x86-64 AVX/AVX2（256 位）
@asm_reg_x64_zmm    x86-64 AVX-512（512 位）
@asm_reg_x86        x86 专用寄存器
@asm_reg_arm64      ARM64 专用寄存器
@asm_reg_arm64_v    ARM64 NEON（128 位）
@asm_mem            内存操作数类型（C 侧映射为 void *），作为「类型」使用
```

- 这些名字由 `src/checker/type_from_ast.uya:613-635` 与 `src/codegen/c99/types.uya:910-942` 识别；`@asm_mem(expr)` 这类调用形式不存在，内存操作数直接传 `&T` / `&const T` 指针操作数

**平台检测**：`@asm_target()` 无实参，返回当前平台枚举值（按整数使用，`src/parser/primary.uya:1157-1179`）：

```
x86_64_linux = 0, x86_64_macos = 1, x86_64_windows = 2,
arm64_linux  = 3, arm64_macos  = 4, arm64_windows  = 5, riscv64_linux = 6
```

```uya
const target: i32 = @asm_target();

if target == 0 {
    // x86-64 Linux
} else if target == 3 {
    // ARM64 Linux
}
```

- `@asm_target` 是内置名字，**不能**写成 `enum @asm_target { ... }`；也没有 `.x86_64_linux` 这种省略枚举名的变体写法（参照 `tests/test_asm_target.uya`）

**详细说明**：见 [uya.md](./uya.md#19-内联汇编) 内联汇编章节

### 特殊表达式

```
primary_expr   = literal | ID | 'self' | '(' expr ')' | array_literal | tuple_literal
               | struct_literal | enum_literal | specialize_expr
               | '@' BUILTIN_ID [ '(' arg_list ')' ]
                # 可书写的内置名以 src/lexer.uya:1316-1372 的白名单为准：
                # size_of align_of len max min params va_start va_end va_arg va_copy
                # src_name src_path src_line src_col func_name embed embed_dir c_import
                # mc_eval mc_code mc_ast mc_error mc_get_env mc_type mc_source
                # async_fn await frame naked_fn align syscall ptr_from_usize usize_from_ptr
                # error_id error_name print println asm asm_target vector mask
                # 白名单外的名字（如 @asm_reg_x64 / @asm_mem）是 lexer 错误，不是语法错误
specialize_expr = ID '<' type_arg_list '>'   # 只在后缀链首、且回看能消解为泛型实参时成立；`ID '{'` 一律按 struct_literal 解析
range          = expr '..' [ expr ]
slice_op       = '[' expr ':' expr ']'  // 切片操作；典型为 &base[start:len]；base 可为标识符、数组字面量或 STRING（0.49.41）
struct_literal = ID '{' field_init_list '}'
field_init_list = [ field_init { ',' field_init } ]
field_init     = ID ':' expr
array_literal  = '[' expr_list ']' | '[' expr ':' expr ']'  # 数组字面量；重复形式 [value: N] 与类型 [T: N] 一致；空列表 [] 表示未初始化（仅当变量类型已明确时可用）
tuple_literal  = '(' expr_list ')'  # 元组字面量，如 (10, 20, 30)
enum_literal   = ID '.' ID  # 枚举字面量，如 Color.RED, HttpStatus.OK
expr_list      = [ expr { ',' expr } ]  # 表达式列表，可以为空（空数组字面量 []）
arg_list       = [ expr { ',' expr } [ ',' '...' ] ]  # 可变参数转发：末尾 ... 表示转发剩余参数
pattern_list   = pattern '=>' expr { ',' pattern '=>' expr } [ ',' 'else' '=>' expr ]
pattern        = literal | ID | '_' | enum_pattern | union_pattern
struct_pattern = ID '{' field_pattern_list '}'   # 见下方「实现核对」：当前不支持
field_pattern_list = [ field_pattern { ',' field_pattern } ]
field_pattern  = ID ':' (literal | ID | '_')
tuple_pattern  = '(' tuple_pattern_list ')'      # 见下方「实现核对」：当前不支持
tuple_pattern_list = pattern { ',' pattern }
enum_pattern   = ID '.' ID  # 枚举模式，如 Color.RED, HttpStatus.OK
union_pattern  = '.' ID [ '(' (ID | '_') ')' ]  # 联合体模式，如 .i(x)、.f(_)
error_pattern  = 'error' '.' ID                  # 见下方「实现核对」：当前不支持
literal        = NUM | STRING | CHAR | 'true' | 'false' | 'null'
```

> **实现核对（2026-10-22）**：上面保留的 `struct_pattern` / `tuple_pattern` / `error_pattern`
> 产生式**当前解析器都不接受**，属设计预留而非可用语法。实测：
> - `P { x: 1, y: _ } => ...` → `意外的 token '{'`
> - `(1, _) => ...` → `意外的 token '('`
> - `.Err(error.Overflow) => ...` → `意外的 token 'error'`
> - `.RED => ...`（裸点号枚举模式）→ `意外的 token '=>'`，枚举要写全 `Color.RED`
>
> **当前真正可用**的模式只有：整数字面量、`Color.RED`（全限定枚举）、变量绑定 `v`、
> 通配符 `_`、`else`、以及联合体变体 `.name(x)` / `.name(_)`。
> 另：`match` 表达式**必须**包含 `else` 或通配符/变量绑定兜底分支，否则报
> 「match 必须包含 else 分支或变量绑定/通配符」（负例 `tests/error_match_missing_else.uya`）。

### 模块系统

```
# 导出不是独立产生式：`export` 是各声明自身的一个可选前缀（见 declaration 与各 *_decl 产生式）。
# 若把 `export_decl` 写成 `'export' (fn_decl | ...)`，而 fn_decl 自身又含 [ 'export' ]，
# 语法就会允许 `export export fn`，与实际解析器不符 —— 故此处只给说明，不再给产生式。
import_stmt    = 'use' module_path [ 'as' ID ] ';'
module_path    = ID { '.' ID }
```

**说明**：
- **导出语法**：使用 `export` 关键字标记可导出的项（前缀写在声明最前面，`export opaque struct` 亦然）
  - `export fn public_function() i32 { ... }`
  - `export struct PublicStruct { ... }`
  - `export opaque struct Resource { handle: usize }`（模块外不可构造、不可访问字段）
  - `export interface PublicInterface { ... }`
  - `export type MyInt = i64;`
  - `export const PUBLIC_CONST: i32 = 42;`
  - `export var debug_mode: i32 = 0;`
  - `export error PublicError;`
  - `export mc twice(x: expr) expr { ${x} + ${x}; }`
  - `export extern fn printf(fmt: *byte, ...) i32;`（导出外部 C 函数声明，无函数体，链接到 C 标准库）
  - `export extern fn strcmp(s1: &const byte, s2: &const byte) i32 { ... }`（Uya 实现，以裸函数名导出）
- **导入语法**：
  - 导入整个模块：`use std.io;`（使用时需要模块前缀：`std.io.read_file()`）
  - 导入特定项：`use std.io.read_file;`（直接使用：`read_file()`）
  - 导入并重命名：`use std.io as io_module;`（使用别名：`io_module.read_file()`）
- **模块路径**：使用 `.` 分隔，相对于项目根目录
  - 项目根目录：`main` 模块
  - 子目录：`std/io/` → `std.io`
- **同目录文件合并规则**：
  - 同一目录下的所有 `.uya` 文件都属于同一个模块
  - 模块路径由目录路径决定，不包含文件名
  - 例如：`std/io/file.uya` 和 `std/io/stream.uya` 都属于 `std.io` 模块
  - 编译器会自动收集同一目录下的所有 `.uya` 文件，合并为一个模块
- 详细说明见 [uya.md](./uya.md#15-模块系统)

### 外部函数接口（FFI）

```
extern_decl    = 'extern' [ STRING ] 'fn' ID '(' [ param_list ] ')' type (';' | '{' statements '}')
               | 'extern' 'union' ID '{' field_list '}'  # 外部 C 联合体声明
               | 'extern' ( 'const' | 'var' ) ID ':' type ';'  # 外部 C 变量声明（0.43 新增）
```

**说明**（0.43 新增 `extern "libc"` 和 `extern` 变量）：
- `extern fn name(...) type;` - 声明外部 C 函数（导入，供 Uya 调用）
- `extern "libc" fn name(...) type;` - 声明 C 标准库函数（与 `extern fn` 等价）
- `extern fn name(...) type { ... }` - 导出 Uya 函数为 C 函数（导出，供 C 调用）
  - 导出的函数可以使用 `&name` 获取函数指针，传递给需要函数指针的 C 函数
  - 函数必须使用 C 兼容的类型（FFI 指针类型 `*T`、基本类型等）
- **byte 类型映射规则**（0.43 新增）：`byte` → `char`（C 字符类型，与 C 标准库兼容）
- **extern 变量支持**（0.43 新增）：
  - `extern const name: type;` - 导入只读 C 全局变量，生成 `extern const type name;`
  - `extern var name: type;` - 导入可变 C 全局变量，生成 `extern type name;`
  - 示例：`extern const errno: i32;` `extern var optind: i32;` `extern const stdout: *void;`
- 所有 `struct` 统一使用 C 内存布局，无需 `extern` 关键字
- 结构体可以包含所有类型（包括切片、interface 等），编译器自动生成对应的 C 兼容布局

### 错误处理

```
error_decl     = 'error' ID ';'                              # 预定义错误声明（可选）
error_type     = 'error' '.' ID                              # 错误类型引用（预定义或运行时错误）
```

**说明**：
- **预定义错误**（可选）：使用 `error ErrorName;` 在顶层声明，属于全局命名空间
- **运行时错误**：使用 `error.ErrorName` 语法直接创建，无需预先声明
- 两种错误类型在语法上使用相同的引用形式 `error.ErrorName`
- **error_id 稳定性**：`error_id = hash(error_name)`，相同错误名在任意编译中映射到相同 `error_id`；hash 冲突时编译器报错
- 详细说明见 [uya.md](./uya.md#2-类型系统) 错误类型部分

### 字符串插值

```
string_interp  = '"' { segment } '"'
segment        = TEXT | '${' expr [ ':' spec ] '}'
spec           = flag* width? precision? type
flag           = '#' | '0' | '-' | ' ' | '+'
width          = NUM | '*'
precision      = '.' NUM | '.*'
type           = 'd' | 'u' | 'x' | 'X' | 'f' | 'F' | 'e' | 'E' | 'g' | 'G' | 'c' | 'p'
```

### 注释

```
shebang_comment = '#!' .* '\n'  # 仅当出现在文件首两个字节
line_comment   = '//' .* '\n'
block_comment  = '/*' .* '*/'
```

### 词法规则

```
identifier     = [A-Za-z_][A-Za-z0-9_]*
NUM            = integer | float
integer        = decimal_integer | hex_integer | octal_integer | binary_integer
decimal_integer = [0-9] ( [0-9] | '_' )* [ int_suffix ]?
hex_integer    = '0' [xX] [0-9a-fA-F] ( [0-9a-fA-F] | '_' )* [ int_suffix ]?
octal_integer  = '0' [oO] [0-7] ( [0-7] | '_' )* [ int_suffix ]?
binary_integer = '0' [bB] [01] ( [01] | '_' )* [ int_suffix ]?
float          = [0-9] ( [0-9] | '_' )* '.' [0-9] ( [0-9] | '_' )* [ exponent ]? [ float_suffix ]?
               | [0-9] ( [0-9] | '_' )* exponent [ float_suffix ]?

int_suffix     = 'i8' | 'i16' | 'i32' | 'i64'
               | 'u8' | 'u16' | 'u32' | 'u64'
               | 'usize'

float_suffix   = 'f32' | 'f64'
exponent       = [eE] [+-]? [0-9] ( [0-9] | '_' )*
STRING         = '"' { string_char } '"' | '`' { character } '`'
string_char    = [^"\\] | escape_sequence
escape_sequence = '\\' ( 'n' | 'r' | 't' | '\\' | '"' | '0' | 'x' HEX HEX | 'u' HEX HEX HEX HEX )
CHAR           = '\'' ( [^'\\] | escape_sequence_char ) '\''
escape_sequence_char = '\\' ( 'n' | 'r' | 't' | '\\' | '\'' | '0' | '"' | 'x' HEX HEX | 'u' HEX HEX HEX HEX )
HEX            = [0-9a-fA-F]
TEXT           = [^${}]+
```

**说明**：
- 整数字面量默认类型为 `i32`，浮点字面量默认类型为 `f64`
- 下划线 `_` 可出现在任意两个数字之间，不能出现在开头、结尾或连续出现
- 下划线不能紧跟在进制前缀之后（如 `0x_FF` 非法）
- 字符串字面量包括普通字符串 `"..."` 和原始字符串 `` `...` ``（无转义）；语义上自动带 `\0` 结尾；可初始化/赋值给 `[byte: N]`、**`&[const byte]`**（**0.49.43**）、`&byte`、`*byte`（详见 uya.md 文件与词法·字符串字面量）；**赋值语句左值**可为标识符或**成员访问链**（**`a.b.c = "..."`**）
- **`escape_sequence` / `escape_sequence_char`**（**0.49.42**）：**`\x`** 后须恰好两个 **`HEX`**；**`\u`** 后须恰好四个 **`HEX`**，按 UTF-8 展开（字符串）或要求值 **≤255**（字符，见 uya.md §1.4）
- 字符字面量 `'x'` 类型为 `byte`，可赋值给 `byte`

### 可选特性（泛型和宏）

**泛型语法说明**：
- 泛型语法已整合到主要声明中（见[函数声明](#函数声明)、[结构体声明](#结构体声明)、[接口声明](#接口声明)）
- 使用尖括号 `<T>`，约束紧邻参数 `<T: Ord>`，多约束连接 `<T: Ord + Clone + Default>`
- **函数泛型示例**：`fn max<T: Ord>(a: T, b: T) T { ... }`
- **结构体泛型示例**：`struct Vec<T: Default> { ... }`
- **接口泛型示例**：`interface Iterator<T> { ... }`
- **方法泛型示例**（0.47 新增）：
  ```uya
  struct Container<T> {
      value: T,
      fn as_type<U>(self: &Self) U { return self.value as U; }
  }
  // 调用：c.as_type<i64>()
  ```
- **类型参数使用示例**：`Vec<i32>`, `Iterator<String>`

**显式宏语法（可选特性）**：
```
macro_decl     = [ 'export' ] 'mc' ID '(' [ param_list ] ')' return_tag '{' statements '}'
param_list     = param { ',' param }
param          = ID ':' param_type [ '=' expr ]   # 默认值可解析，但展开阶段未实现绑定（见说明）
param_type     = 'expr' | 'stmt' | 'type' | 'pattern' | 'ident'
return_tag     = 'expr' | 'stmt' | 'struct' | 'type'
macro_call     = ID '(' arg_list ')'
```

**说明**：
- `mc` 关键字用于声明宏
- `export mc` 可导出宏供其他模块使用
- 参数类型：`expr`（表达式）、`stmt`（语句）、`type`（类型）、`pattern`（模式）、`ident`（标识符）
- 返回标签：`expr`（表达式）、`stmt`（语句）、`struct`（结构体成员）、`type`（类型标识符）
- 参数默认值：**解析器接受** `p: expr = <表达式>` 语法（`default_value` 已从产生式中删除，见下方说明），
  但**展开阶段没有把它绑定到实参** —— 省略该实参时宏体里对该参数的引用会保留成裸标识符，
  C 层报 `undeclared identifier`。因此当前**不要依赖宏参数默认值**，缺参数时请显式传值。
  注意**普通函数参数没有默认值语法**（`fn f(a: i32 = 5)` 是语法错误）
- 宏调用语法与普通函数调用完全一致
- 跨模块宏导入：`use module.macro_name;`
- **宏是卫生宏（hygienic macro）**：宏体内**引入的**局部绑定（`const`/`var` 局部变量、`for` 循环变量、
  宏内嵌套 `fn` 的参数、`catch |err|` 的错误变量）在展开时被重命名为唯一名，不会捕获或遮蔽调用处的同名标识符。
  **宏参数**与 `const x = @mc_eval(...)` / `const x = @mc_type(...)` 的绑定语义不变；`fn_decl_name`
  首版保持原样不重命名。实现见 `src/checker/macro_expand.uya` 的 `hygiene_enabled` /
  `create_hygiene_name`，语法（BNF）不变，规则本身见 [uya.md §25.2.2](./uya.md#2522-卫生宏宏卫生化)；
  回归 `tests/test_macro_hygiene.uya`。
- 详细说明见 [uya.md](./uya.md#25-宏系统)

**编译时类型反射（@mc_type 与 TypeInfo）**：
- `@mc_type(expr)` 为内置函数，参数为类型或表达式，返回 `TypeInfo` 结构体（编译时求值）。
- **TypeInfo**（由标准库 `lib/std/macro_typeinfo.uya` 定义或 codegen 自动生成）：包含 `name`（*i8）、`size`、`align`、`kind`、`is_integer`、`is_float`、`is_bool`、`is_pointer`、`is_array`、`is_void`、`field_count`、`fields`（固定长度数组）；**获取 fields 大小请用 `@len(info.fields)`**（不导出容量常量），用于宏内类型查询与 `for info.fields` 编译期展开。
- **FieldInfo**（同上）：包含 `name`（*i8）、`type_name`（*i8）；在 `for info.fields |var|` 展开时，`var.name` 替换为当前字段名的标识符 AST，`var.type_name` 替换为当前字段类型的类型 AST。详见 [uya.md §25.4.2](./uya.md#2542-mc_typeexpr) 当前实现小节。
- **宏展开期对 `for info.fields |var|` 的特殊处理**（语义规则，BNF 不变）：在宏体内，当 `for` 的集合表达式为 `expr.fields` 且 **`expr` 为标识符**、该标识符绑定到 `@mc_type(...)` 得到的 TypeInfo 结构体字面量时，在宏展开阶段将该 for **展开为顺序块**（即 `{ body_0; body_1; ... }`，n = field_count）；循环变量 `var` 的 **`var.name`** 在每轮替换为当前字段名的标识符 AST，**`var.type_name`** 替换为当前字段类型的类型 AST。仅对**宏体顶层**的此类 for 触发展开；受体非标识符或未绑定到 TypeInfo 时保持普通 for 语义，不报错。详见 [uya.md §25.6.1](./uya.md#2561-编译期-for-over-typeinfofields)。

**函数返回类型**：
- `type` 在 `fn_decl` 中作为返回类型，可为任意类型产生式，包括 `slice_type`、`error_union_type` 及其组合。
- 合法示例：`fn f() &[byte]`、`fn g() !&[byte]`、`fn h() !i32`。切片与错误联合作为返回值时，语义与 codegen 需支持返回切片结构体（如 `struct { ptr; len; }`）及错误联合的 payload 为切片的情形。


---

## 参考

- [uya.md](./uya.md) - 完整语言规范
- [grammar_quick.md](./grammar_quick.md) - 语法速查手册
- [comparison.md](./comparison.md) - 与其他语言的对比
