词法¶
源文件与编码¶
Lumos 仅接受 Unicode 源码文件,编码必须为 UTF-8、UTF-16 或 UTF-32。
所有内容区分大小写,且不允许 BOM;若检测到 BOM 将直接报错。
标识符¶
语法规则¶
标识符由字母、数字和下划线组成:
- 首字符:必须为字母或下划线
[a-zA-Z_] - 后续字符:可为字母、数字或下划线
[a-zA-Z0-9_]* - 保留字:大部分情况下 Lumos 关键字不可作为标识符使用(见 关键字列表)
- 下划线前缀只分配给非公开成员:以单个下划线开头的标识符被约定为私有或内部使用,虽然语法上仍然有效,但建议遵循这一约定以提高代码可读性。
- 同时添加下划线前后缀只分配给私有成员:以单个下划线开头并以单个下划线结尾的标识符被约定为私有成员,虽然语法上仍然有效,但建议遵循这一约定以提高代码可读性。
var i32 count = 0; // ✓ 有效
val name = "Alice"; // ✓ 有效
i32 _private = 42; // ✓ 有效(下划线前缀表示私有/内部)
i32 x123 = 1; // ✓ 有效
i32 123var; // ✗ 无效(以数字开头)
二进制标识符¶
默认标识符仅允许上述 ASCII 字符的子集,若需要使用其它内容作为名称,必须使用 $"..." 的形式,并遵循 b"..." 的字节串转义规则:
val $"变量" = 10; // ✓ Unicode 标识符
val $"π" = 3.14159; // ✓ 特殊符号
val $"😀" = "emoji"; // ✓ 表情符号
val $"var with spaces" = 42; // ✓ 包含空格
val $"\0\x12\x34\x56" = 0; // ✓ 二进制内容
此时使用这些变量和函数时也需要使用 $"..." 的形式:
println($"变量"); // 输出 10
命名约定¶
虽然语法允许多种形式,但建议遵循以下命名约定以提高代码可读性和一致性:
| 类别 | 风格 | 示例 |
|---|---|---|
| 变量/参数 | snake_case |
max_count, user_name, is_valid |
| 函数 | snake_case |
calculate_sum, handle_event, parse_json |
| 类型/结构体 | PascalCase |
Point, Vector, LinkedList |
常量(lit/imv) |
UPPER_CASE |
PI, MAX_SIZE, DEFAULT_TIMEOUT |
空白字符¶
Lumos 认可的空白字符为 \x20(空格)、\x09(制表符)和 \x0A(换行符)。其它任何字符均不被视为空白字符。
行号在遇到换行符(LF)时递增,列号在换行处重置。回车符(CR, \x0D)本身不增加行号,但仅允许作为 CRLF 序列的一部分(即 CR 必须紧跟 LF);在其他位置出现 CR 将引发词法错误。
行首的空白(空格或制表符)被视为缩进。单个行的缩进必须只使用空格或只使用制表符,混用空格和制表符进行缩进会导致词法错误。
运算符¶
对于运算符,Lumos 采用简单且一致的规则:
- 下列字符可作为运算符的一部分:
! % ^ & * - + = | : < > , . ? / ~ - 采用永远最长匹配原则进行运算符识别。
也就是说,遇到 a+-b 时会被解析为单个 +- 运算符,而不是 + 运算符后跟 - 运算符;如果未定义 +-,则会报错。
例如,我们可以用带斜线的标识符为运算符提供实现:
// 我们用 `\mul` 来表示 `*` 运算符
// `\mul_mul` 对应 `**` 运算符
def \mul_mul(int a, int b) -> int {
return pow(a, b);
}
自定义运算符不得超过 4 个字符长度。
相关内容:语法入口见 语法。