rokdocs
v0.1

3.2. 우선순위와 결합성

연산자에는 우선순위 (precedence) 와 결합성 (associativity) 이라는 두 가지 속성이 있습니다. 하나의 표현식 안에 여러 연산자가 함께 등장할 때, 이 두 속성이 어떤 모양의 트리가 만들어질지를 결정합니다.

3.2.1. 우선순위

a + b * c       →   a + (b * c)              // * 가 + 보다 강함
a * b + c       →   (a * b) + c              // 마찬가지
a < b + c       →   a < (b + c)              // + 가 < 보다 강함

우선순위 값은 정수로 표현하며, 더 큰 값을 가진 연산자가 먼저 묶이게 됩니다.

3.2.2. 결합성

a - b - c       →   (a - b) - c             // 좌결합
a ?? b ?? c     →   a ?? (b ?? c)           // 우결합 (예시)
a < b < c       →   ?                        // 비결합 (체이닝 금지)

결합성은 다음 세 가지 중 하나로 정해집니다.

표기의미
left좌측부터 묶임. a OP b OP c = (a OP b) OP c
right우측부터 묶임. a OP b OP c = a OP (b OP c)
none체이닝 금지. a OP b OP c 는 컴파일 에러

3.2.3. 우선순위와 결합성 표

모든 내장 연산자 토큰의 우선순위와 결합성은 언어가 고정하며, 아래 표가 그 단일 권위입니다. 표준 라이브러리의 #[infix] / #[prefix] / #[postfix] 는 토큰과 트레잇 메서드를 연결할 뿐, 우선순위나 결합성을 정하거나 바꾸지 않습니다.

우선순위 등급

등급  연산자                                           결합
13   후위: 멤버 접근 (.), ?., 메서드 호출, 인덱싱, ?   좌
12   전위 단항: - ! ~ √ await                          -
11   as is (후위 형 변환 / 형 검사)                    좌
10   << >>                                             좌
 9   ∘ (함수 합성)                                     좌
 8   * / % %% × ⋅ ÷ ∩                                  좌
 7   + - ∪                                             좌
 6   & ^                                               좌
 5   |                                                 좌
 4   == != < > <= >= ≡ ≠ ≤ ≥ ∈ ∉ ⊂ ⊆                   비결합
 3   &&                                                좌
 2   ||                                                좌
 1   ?? (null 합체)                                    우
 0   .. ..= (범위)                                     비결합
-1   = += -= *= /= %= %%= &= |= ^= <<= >>= (대입)      우

표의 Unicode 연산자 (× ⋅ ÷ ∩ ∪ ∘ √ ≡ ≠ ≤ ≥ ∈ ∉ ⊂ ⊆) 는 1.10.3 의 고정 토큰입니다. 3.2 표에 없는 확장 토큰 (1.10.4) 은 새 단계를 만들지 않고, 등록할 때 like = "+" 처럼 지정한 기존 토큰의 단계와 결합성을 그대로 따릅니다 (6.7.2).

중요

?? 와 .. 의 상대 우선순위: ?? (prec=1) 는 범위 연산자 .. / ..= (prec=0) 보다 강하게 묶입니다. 따라서 a ?? 0..3 은 (a ?? 0)..3 으로 묶이며, 범위 연산자는 대입을 제외한 모든 이항 연산자보다 약합니다 (a || b..c 는 (a || b)..c). 두 연산자는 트레잇으로 디스패치되지 않고 언어가 직접 처리합니다 - ?? 는 합 타입 위의 언어 수준 desugar (3.8.4) 이고, 범위는 언어가 여섯 형태를 별개의 표현식으로 인식하는 구문 (3.7) 이기 때문입니다. 범위 연산자는 비결합이므로 a..b..c 는 컴파일 에러입니다.

중요

try 와 catch / finally 의 결합: 에러 제어 흐름 의 try / try? / try! 와 catch / finally 절도 트레잇 연결이 없는 언어 구문입니다. try 는 전위 형태이지만 표의 전위 단항 연산자 (prec=12) 와 달리 오른쪽 식 전체를 덮습니다. 그 피연산자는 catch / finally 절, 문장 종결자 ;, 닫는 괄호, 콤마 앞까지 이어지므로 try a + b() 는 try (a + b()) 입니다. catch / finally 절은 대입 (prec=-1) 보다 강하고 그 밖의 모든 연산자보다 약하게 묶여, 왼쪽의 식 전체에 붙습니다. 따라서 try parse(s) catch _ { 0 } 은 (try parse(s)) catch _ { 0 } 이고, x = try f() catch _ { 0 } 은 x = ((try f()) catch _ { 0 }) 입니다.

중요

await: await 는 - 나 ! 처럼 prec=12 의 전위 단항 연산자이므로, 피연산자는 단항 식입니다: await f() == x 는 (await f()) == x 입니다 (4.12.2).

중요

as 와 is: 두 후위 연산자는 트레잇 연결이 없는 언어 구문이며, 같은 등급 (prec=11) 으로 묶입니다. 전위 단항보다 약하고 산술보다 강하므로 -x as i64 는 (-x) as i64, a + b is i32 는 a + (b is i32) 입니다. e is T 의 결과는 bool 입니다 (2.2.5).

참고

점-접두 (broadcast) 연산자의 우선순위: .+, .*, .&&, .%% 같은 점-접두 형태의 우선순위와 결합성은 점 없는 형태와 동일합니다. 별도의 행으로 표기하지는 않으나, 모든 점-접두 토큰은 대응하는 일반 토큰의 등급을 그대로 따릅니다. 예: .+ 는 + 와 같은 prec=7 left, .&& 는 && 와 같은 prec=3 left.

참고

시프트 연산이 산술 연산보다 강하게 묶인다는 점이 C 와 다른 부분입니다. 따라서 1 + 2 << 3 은 1 + (2 << 3) = 17 으로 묶이게 됩니다. 직관에서 벗어난다고 느껴지신다면 괄호로 명시해 주시는 편이 적합합니다.

같은 토큰의 다중 위치

같은 토큰이 전위, 이항, 후위로 모두 등장할 수 있는 경우 (예를 들어 -) 에는 각 위치별로 별개의 우선순위가 정해집니다 (보통은 전위가 이항보다 강합니다).

-a + b          →   (-a) + b              // 전위 - 가 + 보다 강함

3.2.4. 충돌

우선순위는 표가 고정하므로 등록끼리 우선순위가 충돌하는 일은 없습니다. 같은 (토큰, 위치) 에 서로 다른 트레잇을 연결하는 것은 6.7.5 에 따라 컴파일 에러입니다.

3.2.5. 비교 체이닝 금지

경고

수학적 직관 (a < b < c 가 a < b 그리고 b < c 를 의미) 에 따른 체이닝은 rok 에서는 허용되지 않습니다.

비교 연산자 (<, >, <=, >=, ==, !=) 는 3.2.3 표에서 모두 비결합입니다.

a < b < c       // ERROR: 체이닝 금지
a == b == c     // ERROR

원하는 의미가 있다면 다음과 같이 명시적으로 적어 주셔야 합니다.

a < b && b < c

이러한 결정에는 두 가지 근거가 있습니다.

  • 비교의 결과는 bool 인데, 그 bool 을 다시 비교한다는 것은 수학적 직관과 어긋나기 때문입니다.
  • 체이닝을 받아들이려면 별도의 체이닝 규칙이 필요한데, 그 규칙은 다른 연산자와 일관되지 않게 되기 때문입니다.

따라서 명시적으로 && 를 사용하는 방식이 가장 단순하고 일관된 표현이라 할 수 있습니다.

3.2.6. 괄호로 강제 묶기

위의 규칙에 따라 만들어지는 트리가 의도한 모양과 다를 때에는, 괄호를 사용해 강제로 묶어 주실 수 있습니다.

a + b * c       →   a + (b * c)             // 기본 묶임
(a + b) * c     →   (a + b) * c             // 명시적

괄호는 어휘 단계와 구문 단계에서 그룹화 토큰으로 동작하며, 트리의 모양을 직접 제어할 수 있게 합니다.

3.2.6a. 구현 한도

연산자 / 후위 연산의 사슬이 4096 개를 넘거나 중첩이 256 보다 깊으면 에러입니다. 이것은 rok 의 한도입니다 (구현이 정함, 0.4.4).

3.2.7. 우선순위가 같고 결합성이 다른 두 토큰

3.2.3 표에서는 한 단계 안의 토큰이 모두 같은 결합성을 가지므로 이런 경우는 생기지 않습니다. 확장 토큰도 like 로 기존 토큰의 결합성을 그대로 따르므로 마찬가지입니다.

GitHub에서 이 페이지 고치기