# 表达式与语句

> 

本文档收敛 Dujie 的字面量、控制流、运算、推导边界、语句模型和语言级错误行为。

## 总体原则

- Dujie 采用表达式优先的风格
- `if` 和 block 都可以作为表达式
- 赋值、`break`、`continue` 属于语句，不参与普通表达式求值
- `unit` 是正式类型，用于表示“无值”

## 字面量

### 基础字面量

- `int`
- `float`
- `bool`
- `string`
- `rune`

当前公开整数类型只有 `int`。

### `string`

- 普通字符串使用 `"..."` 表示
- 支持转义：`\\`、`\"`、`\n`、`\r`、`\t`、`\u{...}`
- `string` 是文本类型，不是字节数组

### `rune`

- `rune` 使用 `'a'` 形式
- 支持转义：`\\`、`\'`、`\n`、`\r`、`\t`、`\u{...}`
- 转义展开后必须恰好表示一个字符，否则是词法错误

### 插值字符串

- 插值字符串使用反引号：``hello ${name}``
- 插值片段写作 `${expr}`
- 整体结果类型是 `string`
- 插值允许任意类型

插值使用的是展示语义，不是序列化语义：

- 基础类型按自然文本形式展示
- `none` 在插值上下文里等价于空字符串
- `some(v)` 等价于插入 `v` 的展示结果
- `list / map / struct / widget / iter / func` 使用统一摘要展示，不展开结构

## 容器与聚合字面量

### `list`

- 语法：`[]`、`[1, 2, 3]`
- 元素必须同类型
- 不做 `int` / `float` 混合推导
- `T` 可在上下文需要时提升到 `opt<T>`

例如：

```dj
[1, 2, 3]
["a", none]
```

### `map`

- 语法：`{ "a": 1, "b": 2 }`
- key 必须同类型
- value 必须同类型
- `map` key 当前只允许：

  - `int`
  - `bool`
  - `rune`
  - `string`

第一阶段不引入联合类型。

### `struct` 构造

- 语法：`Person { name: "snow", age: 18 }`
- 这是具名类型构造，不是匿名对象字面量
- 所有字段必须显式提供
- 未知字段、重复字段、缺字段都是编译错误

## `struct`

`struct` 是名义类型，不是结构类型。

规则：

- 只支持具名字段
- 字段声明写作 `name: Type`
- 不支持 tuple struct
- 不支持按数字索引访问
- 字段顺序不构成类型语义
- 第一阶段不支持字段默认值

类型兼容：

- 两个 `struct` 即使字段完全一致，只要名字不同，就是不同类型
- 不支持 `struct` 和 `map` 之间自动互转

字段类型：

- 可包含基础类型
- 可包含 `list / map / opt`
- 可包含其他 `struct`
- 可包含 `widget`
- 第一阶段不建议 `iter<T>` 作为字段类型

递归：

- 允许通过 `opt<T>`、`list<T>`、`map<K, T>` 间接递归
- 不允许字段直接按值引用自身类型

### 多行格式与尾逗号

- 单行 `list / map / struct` 可带尾逗号，也可不带
- 多行 `list / map / struct` 必须带尾逗号

## 类型推导边界

- `let x = expr` 只在 `expr` 类型唯一时允许推导
- `[]`、`{}`、`none` 不能独立推导类型
- `if` 两个分支类型必须一致
- 空容器和 `none` 需要依赖上下文或显式标注

例如：

```dj
let a = 1
let b: list<int> = []
let c: opt<string> = none
```

## `opt<T>`

`opt<T>` 的语言级构造和判定：

- `none`
- `some(x)`
- `x is none`
- `x is some(v)`

规则：

- `opt<T>` 不支持比较运算
- 参数类型为 `opt<T>` 时允许省略
- `T` 可自动提升为 `some(T)`

## `any`

`any` 是边界类型，不是万能类型。

当前语义：

- `T -> any` 允许
- `any -> T` 不做隐式恢复
- 第一阶段使用 `is` 做显式收窄

支持的最小 `is` 形式：

```dj
x is T
x is T(v)
```

当前稳定支持的收窄目标首先是基础类型：

- `int`
- `float`
- `bool`
- `rune`
- `string`

## 表达式

### 匿名函数表达式

匿名函数是表达式。

形式与普通函数相同，只是没有名字：

```dj
func(x: int) -> string {
    `#${x}`
}
```

当前边界：

- 允许捕获外部变量
- 主要用于目标参数类型已知的回调位置
- 不作为完整一等函数值系统单独展开

### `if` 表达式

- `if` 是表达式
- `if` 和 `else` 都必须存在
- 条件必须是 `bool`
- 两个分支结果类型必须一致

### block 表达式

- block 的结果类型由尾表达式决定
- 如果没有尾表达式，则结果类型为 `unit`

例如：

```dj
let x = {
    let a = 1;
    a + 1
}
```

## 语句

### `let` / `var`

- `let`：不可变绑定
- `var`：可变绑定

绑定可变性与更新规则：

- `let` 绑定不能重新赋值
- `let` 绑定也不能做原地更新
- `var` 绑定允许重新赋值和原地更新

### 赋值

- `=` 是语句，不是表达式
- 左侧必须是可写左值
- 当前合法左值：

  - 变量名 `x`
  - `xs[i]`
  - `m[k]`
  - `p.name`

### 容器更新

`list` 支持：

- `xs[i]`
- `xs[i] = v`
- `push(v)`
- `pop()`
- `remove(i)`
- `clear()`
- `len()`

`map` 支持：

- `m[k]`
- `m[k] = v`
- `remove(k)`
- `clear()`
- `contains(k)`
- `len()`

统一规则：

- 更新操作只能作用在 `var` 绑定的可写左值上
- 临时值不能更新
- 会修改接收者的方法只能对可写目标调用

运行时行为：

- `list[i]` 越界时 `panic`
- `list[i] = v` 越界时 `panic`
- `list.pop()` 对空列表调用时 `panic`
- `list.remove(i)` 越界时 `panic`
- `map[k]` 缺 key 时 `panic`
- `map[k] = v` 缺 key 时直接插入
- `map.remove(k)` 缺 key 时 `panic`

### `return`

- 返回类型必须与函数声明一致
- `unit` 函数可写 `return;`
- 非 `unit` 函数不能写裸 `return;`

### `break` / `continue`

- 都是语句，不是表达式
- 只允许出现在 `for` 循环体中

### `for in`

形式：

```dj
for x in expr {
    ...
}
```

当前可迭代类型：

- `list<T>`
- `iter<T>`

当前不支持：

- `for (i, x) in xs`
- `for (k, v) in map`
- 字符串迭代
- 解构绑定

## `panic`

`panic` 是内建能力，用于主动中止执行。

当前规则：

- 形式：`panic(message: string)`
- 参数只接受 `string`
- 它不会正常返回
- 在类型检查上，允许出现在任意需要值的位置

## 运算

### 算术

- `+ - * / %` 只对数值类型开放
- 不支持 `int` / `float` 混合运算
- `int op int -> int`
- `float op float -> float`
- `%` 只支持 `int`
- `int / int -> int`
- `float / float -> float`
- 一元负号支持 `int` 和 `float`

### 比较

支持 `==` / `!=`：

- `int`
- `float`
- `bool`
- `rune`
- `string`

支持 `< <= > >=`：

- `int`
- `float`
- `rune`
- `string`

不支持比较：

- `opt<T>`
- `struct`
- `list`
- `map`
- `iter`
- `widget`
- `any`

### 逻辑

- `!` 只接受 `bool`
- `&&` 和 `||` 只接受 `bool`
- `&&` / `||` 使用短路语义

### 显式转换

转换语法采用 `Type(expr)`。

第一阶段只支持：

- `float(int_expr)`
- `int(float_expr)`

其中 `float -> int` 按向零截断处理。

## 成员访问、下标与调用

### 成员访问 `x.y`

- 只对 `struct` 和语言内建对象开放
- `struct` 字段不存在时，编译错误
- 第一阶段不支持 `map` 的点访问

### 下标访问 `x[y]`

- `list<T>[int] -> T`
- `map<K, V>[K] -> V`

运行时行为：

- `list` 越界时 `panic`
- `map` 缺 key 时 `panic`

### 调用 `f(...)`

- 调用结果类型由函数声明返回类型决定
- 参数匹配规则见《函数与调用》

## `iter<T>`

`iter<T>` 是遍历用的中间类型，不是常规稳定容器。

允许：

- 作为函数参数或返回值
- 用于 `for in`
- 通过 `collect()` 显式收集为 `list<T>`

当前核心操作：

- `map`
- `filter`
- `collect`

## 运算符优先级

从高到低：

<steps level="4">

#### 后缀：`x.y`、`x[y]`、`f(...)`

#### 一元：`-x`、`!x`

#### 乘法：`* / %`

#### 加法：`+ -`

#### 比较：`< <= > >=`

#### 相等：`== !=`

#### 逻辑与：`&&`

#### 逻辑或：`||`

#### `if` 表达式

</steps>

约束：

- 不支持链式比较
- 赋值不进入普通表达式优先级体系
- 括号可显式改变优先级

## 语言级错误模型

### 编译错误

能在编译期确定的问题直接报错，例如：

- 类型不匹配
- 未知变量、字段、导入符号
- 调用参数错误
- 对 `let` 做更新
- 非法左值赋值
- `break / continue` 出现在循环外
- 非法字面量和非法转义

### 运行时 `panic`

依赖运行时值的问题进入 `panic`，例如：

- `map[k]` 缺 key
- `list[i]` 越界
- 空列表 `pop`
- 用户显式调用 `panic("...")`

总原则：

- 能在编译期确定的问题，不留到运行时
- 只有依赖运行时具体值的问题，才进入 `panic`
