运算符

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 续行规则——多行表达式请使用 (){} 显式包围。