# 渲染内建

> 

本文档收敛 Dujie 中直接参与最终渲染结果的语言内建：

- `main`
- `element`
- `text`
- `fragment`
- `comment`

它们不按普通函数库看待，而是渲染系统和宿主平台之间的语言级边界。

## `widget`

`widget` 是抽象渲染结果类型。

它不是某一种具体宿主节点类型，而是“可被渲染系统接受的 UI 树值”。

当前规则：

- `widget` 是一等类型
- 可以赋值、传参、返回
- 可以放入 `list<widget>`
- 可以作为 `struct` 字段或 `opt<widget>` 的内部类型
- 不支持比较
- 不能作为 `map` 的 key

## 组件函数

组件函数的判定规则：

- 只有显式返回类型恰好为裸 `widget` 的函数才算组件函数
- `list<widget>`、`opt<widget>`、`map<string, widget>` 等都不算组件函数返回类型
- 判定只看显式签名，不靠函数体推导

组件函数本身仍然是普通 Dujie 函数，只是返回 `widget`。

## 保留内建名

第一阶段将以下名字视为保留内建名：

- `main`
- `element`
- `text`
- `fragment`
- `comment`

用户不能定义同名顶层函数覆盖它们。

## `main`

`main` 是入口 intrinsic，不等同于普通导出函数。

规则：

- `main` 的返回类型必须显式写为裸 `widget`
- `main` 的参数写法按普通 Dujie 函数规则处理
- `main` 不能是泛型函数

也就是说，这些都可以是合法的语言层声明：

```dj
func main() -> widget
```

```dj
func main(title: string, count: opt<int>) -> widget
```

```dj
func main({ title: string, count: int = 0 }) -> widget
```

### 入口适配层

语言层允许用户自由书写 `main` 参数形状，但宿主或代码生成层需要提供与之匹配的入口适配。

当前约定是：

- 如果 `main` 使用位置参数，Rust 侧按顺序暴露对应参数
- 如果 `main` 使用具名参数，Rust 侧可以生成对应的参数结构体来承接输入
- `opt<T>` 在 Rust 侧映射为对应的 `Option<T>`
- 默认值由生成的适配层补齐，不要求 Rust 调用方手动补默认值

例如，类似下面的 Dujie 入口：

```dj
func main(title: string, count: opt<int>) -> widget
```

可以在 Rust 侧暴露为“顺序参数”风格入口；而：

```dj
func main({ title: string, count: int = 0 }) -> widget
```

可以在 Rust 侧暴露为“参数结构体”风格入口。

### 动态边界示例

如果用户本身就把 `main` 写成动态边界形式：

```dj
func main(props: map<string, any>) -> widget
```

则：

- `props["k"]` 缺 key 时 `panic`
- 从 `any` 中取具体值时，使用 `is` 做显式收窄

## `text`

签名：

```dj
text(value: string) -> widget
```

职责：

- 构造文本节点
- 不承担格式化职责

## `fragment`

签名：

```dj
fragment(children: list<widget>) -> widget
```

职责：

- 聚合多个子节点
- 不承诺生成真实宿主节点

规则：

- `children` 可以为空
- 嵌套 `fragment` 在渲染语义上可展平
- `fragment([])` 表示不产生可见子节点

## `comment`

签名：

```dj
comment(value: string) -> widget
```

职责：

- 构造注释或调试节点

规则：

- 不影响布局
- 不影响命中测试
- 不影响事件
- 不影响可访问性结构
- 后端可以选择保留或擦除

## `element`

第一阶段按具名参数函数理解：

```dj
func element({
    name: string,
    props: map<string, any> = {},
    children: list<widget> = [],
}) -> widget
```

规则：

- `name` 必填
- `props` 默认空 `map`
- `children` 默认空 `list`
- `props` 是宿主边界属性字典
- `children` 是显式子节点列表

第一阶段不引入联合类型，因此 `element.props` 保持：

```dj
map<string, any>
```

这代表宿主边界的开放属性集合，不代表普通语言内部推荐的静态数据模型。

## 渲染树语义

普通组件函数最终会展开成由 intrinsic 构成的渲染树。

语言层关心的是渲染语义，而不是中间组件调用层级。

### 子节点顺序

- `children` 顺序有语义
- 子节点不能重排

### `fragment` 展平

如果某个子节点是 `fragment(...)`，渲染时可以将其展平成内部子节点序列。

也就是说，这两者在渲染层可以视为等价：

```dj
fragment(children: [a, b])
fragment(children: [fragment(children: [a]), b])
```

### 当前不定义

第一阶段不定义：

- `widget` 的比较或相等性
- diff 语义
- 渲染后端的具体 Android / iOS / Web 映射细节
- 响应式更新机制
