模块系统

本文档收敛 Dujie 的模块、导入导出、路径规则和入口相关约束。

模块

  • 一个源文件就是一个模块
  • 模块身份由文件路径决定
  • 当前唯一合法源文件扩展名是 .dj

第一阶段不引入额外的模块声明语法。

导入

import 只用于导入其他模块已导出的顶层符号。

当前支持的形态:

import { foo, bar } from "./utils.dj"
import { foo as my_foo } from "./utils.dj"

导入源

当前支持两类导入源:

本地相对路径

注册表模块

本地相对路径

例如:

import { button } from "../components/button.dj"

规则:

  • 必须是静态字符串
  • 必须显式写扩展名
  • 按当前文件所在目录做相对解析

注册表导入

例如:

import { button } from "registry:ui/button.dj"

规则:

  • 必须是静态字符串
  • 必须显式写扩展名
  • 不走本地相对路径解析
  • 版本、缓存、锁定等规则交给注册表和构建系统处理

当前不支持

  • 动态导入
  • import *
  • 默认导入
  • 混合默认导入与具名导入
  • 根路径别名
  • 目录索引魔法
  • 自动补全扩展名

导出

当前仅支持导出顶层:

  • func
  • struct

例如:

export func add(x: int, y: int) -> int {
    x + y
}

export struct Person {
    name: string,
}

当前不支持:

  • 导出局部变量
  • 导出表达式结果
  • export { foo, bar }
  • export * from ...

可见性

  • 不写 export 的顶层符号默认模块私有
  • 其他模块只能访问被 export 的符号
  • 模块内部可直接访问本模块私有顶层符号

名称规则

  • 导入名称进入当前模块顶层命名空间
  • 导入后名称冲突是编译错误
  • 可以使用 as 改名避开冲突

路径解析错误

以下情况属于编译错误:

  • 导入路径非法
  • 导入路径无法解析
  • 同一路径不能唯一解析
  • 循环导入

main 与模块入口

main 是入口相关的保留名字,但模块是否被当作应用入口,由构建或运行系统决定,不由 export 决定。

模块级约束:

  • main 必须是模块顶层 func
  • 一个模块内最多只能有一个 main
  • main 不需要 export
  • main 不能与其他顶层符号重名
  • main 不能是泛型函数
  • 普通库模块可以没有 main

语言层不再单独限制 main 的参数形状:

  • 只要参数声明本身符合 Dujie 普通函数规则即可
  • 位置参数、具名参数、opt<T> 参数、默认值都可以用于 main

main 的渲染语义和入口适配规则见《渲染内建》。