运算符
Aria 提供了丰富的运算符,涵盖算术、赋值、比较、逻辑、位运算以及多种特殊运算符。
算术运算符
基本的数学运算:
val.a = 10 + 3 // 13
val.b = 10 - 3 // 7
val.c = 10 * 3 // 30
val.d = 10 / 3 // 3.333...
val.e = 10 % 3 // 1
自增和自减支持前缀与后缀两种形式:
var.i = 5
i++ // 后缀自增,表达式值为 5,之后 i = 6
++i // 前缀自增,i 先变为 7,表达式值为 7
i-- // 后缀自减,表达式值为 7,之后 i = 6
--i // 前缀自减,i 先变为 5,表达式值为 5
赋值运算符
var.x = 10 // 基本赋值
x += 5 // x = x + 5 → 15
x -= 3 // x = x - 3 → 12
x *= 2 // x = x * 2 → 24
x /= 4 // x = x / 4 → 6
x %= 5 // x = x % 5 → 1
~= 是初始化或获取运算符,仅在变量未定义时赋值:
var.name ~= 'default' // 如果 name 未定义,则赋值为 'default'
位运算赋值:
var.bits = 0b1100
bits &= 0b1010 // 按位与赋值 → 0b1000
bits |= 0b0011 // 按位或赋值 → 0b1011
bits ^= 0b1111 // 按位异或赋值 → 0b0100
bits <<= 2 // 左移赋值
bits >>= 1 // 右移赋值
bits >>>= 1 // 无符号右移赋值
比较运算符
val.a = 10 == 10 // true
val.b = 10 != 5 // true
val.c = 10 < 20 // true
val.d = 10 > 5 // true
val.e = 10 <= 10 // true
val.f = 10 >= 15 // false
~~ 是模糊匹配运算符,主要用于检查一个值是否落在某个 Range 内。对于非 Range 类型,~~ 会退化为相等性检查(等价于 ==)。
val.inRange = x ~~ Range(1, 10) // 检查 x 是否在范围 [1, 10] 内
val.eq = x ~~ 'hello' // 非 Range 类型,等价于 x == 'hello'
逻辑运算符
val.a = true && false // false(逻辑与)
val.b = true || false // true(逻辑或)
val.c = !true // false(逻辑非)
逻辑运算符支持短路求值:&& 在左侧为假时不计算右侧,|| 在左侧为真时不计算右侧。
位运算符
val.a = 0b1100 & 0b1010 // 0b1000(按位与)
val.b = 0b1100 | 0b1010 // 0b1110(按位或)
val.c = 0b1100 ^ 0b1010 // 0b0110(按位异或)
val.d = ~0b1100 // 按位取反
val.e = 1 << 3 // 8(左移)
val.f = 16 >> 2 // 4(右移)
val.g = -1 >>> 28 // 无符号右移
三元运算符
标准三元表达式:
var.result = (x > 0) ? 'positive' : 'non-positive'
Elvis 变体 — 省略中间部分或末尾部分:
var.a = x ? : defaultVal // x 为真返回 x,否则返回 defaultVal
var.b = x ? 'yes' : // x 为真返回 'yes',否则返回 none
可选链
?. 在对象为 none 时安全地返回 none,而不是抛出错误:
val.name = user?.name // user 为 none 时返回 none
val.len = list?.length() // list 为 none 时返回 none
空值合并
?? 在左侧为 none 时返回右侧的值:
val.name = user?.name ?? 'anonymous'
val.port = config?.port ?? 8080
成员检查运算符
in 检查键是否存在于 map 或对象中:
val.m = {'name': 'Aria', 'version': 1}
val.exists = 'name' in m // true
val.missing = 'age' in m // false
instanceof 检查对象是否为指定类的实例:
class Animal {}
class Dog : Animal {}
val.d = new Dog()
val.isDog = d instanceof Dog // true
val.isAnimal = d instanceof Animal // true(支持继承链)
逗号运算符
, 依次求值两个表达式,返回右侧的值(兼容 JS 语义):
val.result = (1 + 2, 3 + 4) // 7
展开运算符
... 用于展开列表或字典:
val.a = [1, 2, 3]
val.b = [0, ...a, 4] // [0, 1, 2, 3, 4]
val.base = {'x': 1}
val.extended = {...base, 'y': 2} // {'x': 1, 'y': 2}
函数箭头
-> 用于定义函数:
var.add = -> {
return args[0] + args[1]
}
运算符优先级
从高到低排列:
| 优先级 | 运算符 | 说明 |
|---|---|---|
| 1(最高) | () [] . ?. | 调用、索引、成员访问 |
| 2 | ++ --(后缀) | 后缀自增自减 |
| 3 | ! - ~ ++ --(前缀) | 一元运算符 |
| 4 | * / % | 乘法、除法、取模 |
| 5 | + - | 加法、减法 |
| 6 | << >> >>> | 位移 |
| 7 | < > <= >= ~~ in instanceof | 比较、成员检查 |
| 8 | == != | 相等 |
| 9 | & | 按位与 |
| 10 | ^ | 按位异或 |
| 11 | | | 按位或 |
| 12 | ?? | 空值合并 |
| 13 | && | 逻辑与 |
| 14 | || | 逻辑或 |
| 15 | ? : | 三元运算符 |
| 16 | , | 逗号(顺序求值) |
| 17(最低) | = += -= *= /= %= ~= 等 | 赋值 |
特殊运算规则
Aria 对不同类型之间的运算有特殊处理:
number + string:如果字符串可以转为数字,则执行数学加法;否则执行字符串拼接string - string:如果双方都可以转为数字,则执行减法;否则从左侧字符串中删除右侧子串list + list:合并两个列表,返回新列表list - value:从列表中移除指定元素map + map:合并两个字典,右侧覆盖左侧的同名键
JS 模式 ASI 续行
JavaScript 模式下的 Aria 解析器支持标准 ASI(自动分号插入)的续行规则:当某一行以二元运算符或成员访问符开头时,自动视为上一行的延续(可跨多个空行)。
// 合法:行首 + 续行
let s = 'a'
+ 'b'
+ 'c';
// 链式方法调用
let result = 'hello'
.toUpperCase()
.trim();
// 逻辑组合
let ok = a
&& b
|| c;
支持续行的起始符号:
| 类别 | 符号 |
|---|---|
| 算术 | + - * / % |
| 逻辑 | && || ?? |
| 位运算 | | ^ & << >> >>> |
| 比较 | == != === !== < > <= >= |
| 三元 | ?(: 由前面的 ? 分支决定) |
| 成员 | . ?. |
不续行的:[、(、=(赋值) —— 这些行首的 token 按标准 JS ASI 规则会被解析为新语句(数组字面量、分组、赋值目标),与旧行切断。
Aria 原生模式(非 JS)也支持换行作为语句结束符,但没有 ASI 续行规则——多行表达式请使用 () 或 {} 显式包围。