칸이지 부호점이 아니다

일본어 셀의 작은 상품 테이블을 인쇄해 보니, 이전의 Unicode 작업은 올바른 첫걸음이고, 이 일에는 잘못된 도구임을 알았다. 부호점을 세면 다섯 글자 인사는 폭 5, 하지만 터미널은 10칸으로 그린다. 정렬에는 표시 폭 —— East Asian Width —— 이 필요하고, 부호점 수가 아니다. 수정은 순 라이브러리 Mere의 wcwidth-lite로, UTF-8을 날 나눗셈과 레인지 표로 decode하고, 라이브러리 코드의 거처이기에 4 backend에 일제히 착지했다.

mereunicodestdlibbackendslanguage-design

이전 이야기가 언어에 문자열의 부호점 뷰를 주어, 일본어 단어의 바이트가 아니라 글자를 셀 수 있게 했다. 이 probe는, 그 뷰가 —— 옳은 것임에도 —— 여전히 잘못된 측정인 곳을 찾았다. 그리고 이 구별은, 텍스트를 다루는 모든 언어가 언젠가 맞닥뜨리는 것이다.

다섯 글자, 열 칸

probe는 작았다: 이름 열이 있는 상품 테이블을, ASCII와 일본어 항목을 섞어 인쇄하고, 열을 맞춘다. 부호점 수 함수로 pad하니, 행이 눈에 띄게 들쭉날쭉해졌다 —— 일본어 행이 짧게 앉았다. 이유는, 터미널이 부호점당 한 칸을 그리지 않는 것이다. CJK 문자, 전각형, 이모지는 각각 두 칸으로 그리고, 결합 기호는 0칸으로 그린다. 다섯 부호점의 인사는 터미널 열 칸을 차지하고, 부호점 수는 —— 「몇 글자인가」에는 옳지만 —— 「이것은 몇 칸을 차지하는가」에는 단적으로 잘못된 수다. 이것은 두 이야기 전의 바이트 대 문자열 구별과 같은 교훈의 한 단 위다: 바이트, 부호점, 표시 칸은 같은 문자열의 세 개의 다른 측정이고, 프로그램은 실제로 뜻하는 쪽을 구해야 한다. 정렬이 뜻하는 것은 칸이다.

wcwidth를, 라이브러리에서, 모든 backend에

수정은 표시 폭 함수다: East Asian Width, wcwidth-lite의 방식으로 —— CJK, 전각, 이모지 레인지는 2, 결합 기호는 0, 그 외는 1로 센다 —— 에, 그 위에 세운 좌우 pad 함수. 이것을 한 이야기의 가치로 만드는 것은, 그 거처다. 셋 다 평범한 prelude 함수이고, 언어 자체로 쓰였다: UTF-8은 날 나눗셈과 나머지로 decode되고(2바이트열은 하나의 산술식), 폭 표는 주요 블록에 대한 열두 개쯤의 레인지 체크다. 새 builtin은 없고, backend별 C도 IR도 wasm도 없다. 그리고 prelude는 어디서나 돌아야 하므로, compile한 순간 interpreter, C, LLVM, wasm에서 동일하게 존재했다 —— Part 전체의 4방향 분기라는 테마가 뒤집힌다. 라이브러리 코드는 구성상 분기할 수 없기 때문이다. 폭 표는 Unicode 표가 쓰는 16진 경계가 아니라 10진 레인지로 쓰였고, 그것은 약간 아프고, 그리고 16진으로 쓰고 싶었던 수를 10진으로 쓰는 두 번 연속의 probe다 —— 이제 고칠 만한 크기의 papercut이고, 그것이야말로 마지막 이야기가 하는 일이다. 정렬 테이블 example은 ASCII, 일본어, 이모지, 반각 가타카나의 혼재를, 실제로 맞는 괘선으로 그린다, interpreter에서도 C backend에서도 똑같이.

← Back to Mere: 언어를 만들다