diff options
Diffstat (limited to 'docs/design')
| -rw-r--r-- | docs/design/008-module-format.md | 29 | ||||
| -rw-r--r-- | docs/design/018-lifetimes-and-computation.md | 11 |
2 files changed, 30 insertions, 10 deletions
diff --git a/docs/design/008-module-format.md b/docs/design/008-module-format.md index e9fe3ca..e968ecc 100644 --- a/docs/design/008-module-format.md +++ b/docs/design/008-module-format.md @@ -113,7 +113,7 @@ v6에는 뒤에 **i64**가 더해졌다([016](016-bool-and-i64.md)의 2단계): | 71 | MOD | n n → n | 나눗셈을 내림한 나머지. 결과는 나누는 수의 부호를 따른다(0도). 0으로 나누면 `divide` | | 72 | SEND | f… → | 출력 `인자`의 필드 값을 필드 순서대로 받아(u32·수는 n, bool은 bool, 바이트는 b, text는 t) 메시지 페이로드(접두부와 가변 필드)로 만들고 이벤트의 일부로 보낸다. u32 필드의 값이 0–2³²−1의 정수가 아니면 `limit`. 핸들러 전용 | | 73 | OUTER_ROW | → i | 열 안의 집계 블록에서 그 열의 행(집계의 항목은 ROW). 걷기 안의 집계에서는 걷는 항목 | -| 74 | EACH | | 걷기. `인자`의 비트 8–15는 리스트 상태, 16–31은 뒤따르는 블록의 길이 L. 그 L개 명령이 리스트가 시작할 때 가진 항목마다 차례로 핸들러의 코드로 돈다(`ROW`가 항목). 블록은 상태, 그 리스트의 항목(필드 바꾸기, 지우기), 다른 리스트를 바꿀 수 있지만 걷는 리스트에 넣을 수는 없다. 걷는 항목이나 그 앞의 항목을 지우면 걷기가 따라가 다음 항목을 건너뛰지 않는다. 핸들러 전용 | +| 74 | EACH | | 걷기. `인자`의 비트 8–15는 리스트 상태, 16–31은 뒤따르는 블록의 길이 L. 그 L개 명령이 리스트가 시작할 때 가진 항목마다 차례로 핸들러의 코드로 돈다(`ROW`가 항목). 블록은 상태, 그 리스트의 항목(필드 바꾸기, 지우기), 다른 리스트를 바꿀 수 있지만 걷는 리스트에 넣을 수는 없다. 걷는 항목이나 그 앞의 항목을 지우면 걷기가 따라가 다음 항목을 건너뛰지 않는다. 걷기와 LOOP는 서로 안에 8겹까지 둔다. 안쪽의 코드는 바깥 걷기가 도는 리스트에 넣거나 지우지 못한다. 핸들러 전용 | | 75 | LOCAL_LOAD | → n, bool 또는 i | 이벤트의 지역 칸. `인자`의 비트 0–7은 칸(64개), 8–15는 담는 것(0 수, 1 인덱스, 2 bool), 16–31은 인덱스의 리스트. 칸은 이벤트가 시작할 때 0이고 저장되지 않는다. 핸들러와 그 안의 걷기, 그 안의 집계에서 읽는다 | | 76 | LOCAL_STORE | n, bool, i64 또는 i → | 그 칸에 넣는다. 핸들러와 그 안의 걷기에서. 담는 것 3은 i64. 한 핸들러는 한 칸을 한 가지(수, bool, i64, 또는 한 리스트의 인덱스)로만 쓴다 | | 77–79 | I64_ADD I64_SUB I64_MUL | i64 i64 → i64 | 범위를 넘으면 `overflow` | @@ -123,6 +123,8 @@ v6에는 뒤에 **i64**가 더해졌다([016](016-bool-and-i64.md)의 2단계): | 84–85 | I64_MIN I64_MAX | i64 i64 → i64 | | | 86 | I64_FROM | n → i64 | 범위 안의 정수만. 아니면 `limit` | | 87 | NUM_FROM | i64 → n | \|i\| ≤ 2^53일 때만(정확하다). 아니면 `limit` | +| 88 | LOOP | n n 또는 i i → | 세는 반복([018](018-lifetimes-and-computation.md)). `인자`의 비트 0–7은 지역 칸, 비트 8은 i64의 반복, 16–31은 뒤따르는 블록의 길이 L. 낮음과 높음을 꺼내 그 사이의 값마다(낮음부터 높음 앞까지 1씩) 칸에 값을 두고 L개 명령을 돈다. 수는 2^53 안의 정수여야 하고 아니면 `limit`이다. 블록은 둘레 블록의 코드로 돈다(걷기 안이면 `ROW`도 그대로). 실행량은 돌 때마다 L + 1을 센다. 핸들러 전용 | +| 89 | BREAK | | 그것이 든 가장 안쪽의 LOOP나 EACH를 끝낸다(그 블록 안, 조건 안에서도). 스택이 빈 자리에서만. 핸들러 전용 | bool은 실행 중에 수의 칸에 든 0이나 1이고, i64는 같은 8바이트의 정수다. CONST의 인자 2는 i64 상수(값의 8바이트), NUM_TEXT의 인자 2는 i64의 10진 글자다. LOAD·STORE·지역 칸·항목·FIELD·SEND는 i64를 수처럼 옮긴다. FOLD의 종류에 64(PURE_FOLD_INTEGER)를 @@ -160,9 +162,17 @@ bool은 실행 중에 수의 칸에 든 0이나 1이고, i64는 같은 8바이� - 걸러진 표의 필터 블록은 그 리스트의 열로 검증한다. 읽기만 하고 bool 하나를 남기며, 안에 집계를 둘 수 없다. 타입 다음 바이트는 표에만 쓸 수 있다. - 걷기(EACH)의 블록은 그 핸들러의 코드로 따로 검증하되 `ROW`(걷는 리스트의 항목)를 읽을 수 있다. 값을 남기지 않고, - 걷는 리스트에 넣지(LIST_APPEND·LIST_INSERT) 못하며, 안에 다시 걷기를 둘 수 없고(비용 상한), 응답(REPLY)하지 않는다(응답은 - 이벤트에 하나다). 안의 집계는 걷는 항목을 OUTER_ROW로 읽는다. 둘레의 블록은 EACH와 그 블록을 명령 하나로 보고, 앞의 분기가 - 블록 안으로 들어오지 못한다. 걷는 리스트는 줄기만 하므로 한 걷기는 시작할 때의 항목 수 × 블록 길이를 넘지 않는다. + 걷는 리스트에 넣지(LIST_APPEND·LIST_INSERT) 못하며, 응답(REPLY)하지 않는다(응답은 이벤트에 하나다). 안의 집계는 걷는 항목을 + OUTER_ROW로 읽는다. 둘레의 블록은 EACH와 그 블록을 명령 하나로 보고, 앞의 분기가 블록 안으로 들어오지 못한다. 걷는 리스트는 + 줄기만 하므로 한 걷기는 시작할 때의 항목 수 × 블록 길이를 넘지 않는다. +- 반복(EACH와 LOOP, [018](018-lifetimes-and-computation.md))은 서로 안에 8겹까지 둔다. 검증기는 둘레의 걷기들이 도는 리스트의 + 집합을 들고 내려가, 안의 코드가 그 가운데 어느 것에 넣는 것과, 가장 안쪽 걷기의 것이 아닌 것에서 지우는 것을 거절한다. 그래서 + 실행기는 가장 안쪽 걷기의 자리만 고친다. LOOP의 블록은 둘레 블록과 같은 자리(핸들러나 걷기)의 코드로 검증하고 둘레는 LOOP와 + 그 블록을 명령 하나로 본다. LOOP는 수 둘이나 i64 둘을 꺼내고 그 칸을 그 타입의 지역 칸으로 쓴다(한 핸들러에서 한 칸은 한 + 가지다). BREAK는 반복 안에서, 스택이 빈 자리에서만 쓰고 블록 끝으로의 점프로 검증한다. 응답은 어느 반복 안에도 없다. +- 이벤트의 리스트: 플래그 256(PURE_LIST_ROWS)을 가진 리스트는 이벤트가 끝날 때마다 비워지고 저장되지 않으며 되돌리기 기록을 + 쌓지 않는다. 이름은 경로다. `입력.필드`이면 그 메시지의 행 필드가 채우고(키 없이), `let.이름`이면 코드만 채운다(aup의 `let + 이름: list of 레코드`, 키를 둘 수 있다: 플래그 256 + 키 필드 + 1). 저장하지 않는 상태(비트 8)일 수 없다. - 행 필드(타입 5)는 메시지 입력에만 있고(출력은 행을 보내지 않는다), 가리키는 상태는 행 목록이며 그 이름이 `입력 이름.필드 경로`와 같다. 그래서 행 목록 하나는 필드 하나가 채운다. FIELD는 행 필드를 읽지 않는다(행은 리스트로 읽는다). - 인자(종류 6)는 열이 아닌 보기 하나를 가리키고, 보기마다 하나이며, 이름이 `보기 이름.args`다. 핸들러를 갖지 않는다. 그 @@ -171,8 +181,11 @@ bool은 실행 중에 수의 칸에 든 0이나 1이고, i64는 같은 8바이� - 표는 리스트 상태를 가리키고 열은 앞에 나온 표를 가리킨다. 표 밖의 이름은 한 이름공간이고, 열 이름은 표 안에서만 유일하다. -검증된 모듈은 실행 중 스택·타입 검사가 필요 없고, 이벤트 하나의 명령 수는 핸들러 길이 이하다. 집계가 있으면 -블록 길이 × 항목 수(최대 65,536)만큼 더 돈다. 집계 안에 집계가 없으므로 이 곱이 상한이다. +검증된 모듈은 실행 중 스택·타입 검사가 필요 없다. 이벤트 하나가 도는 명령 수는 실행량 예산이 묶는다: 앱이 정하지 않으면 +2^28 명령이다(018: 세는 반복이 들어와 구조만으로는 묶이지 않는다). 집계와 걷기는 시작할 때 블록 길이 × 항목 수를, LOOP는 돌 때마다 +블록 길이 + 1을 센다. 이벤트가 리스트·text·outbox에 더하는 것도 더할 때마다 센다: 저장 형식으로 메모리 예산을 넘는 순간, 또는 +그것을 위해 가진 것 모두(리스트의 저장 기록과 되돌리기 기록 포함)가 2^28 바이트(예산이 더 크면 예산)를 넘는 순간 `memory`로 +실패한다. 이벤트가 끝난 뒤 상태가 예산을 넘는지는 따로 본다. ## 실행 @@ -187,6 +200,10 @@ bool은 실행 중에 수의 칸에 든 0이나 1이고, i64는 같은 8바이� 이벤트 동안 리스트 변경은 되돌리기 기록에 쌓이고, 실패하면 거꾸로 되돌리며 성공하면 지운 항목과 바뀐 text를 해제한다. 항목의 text 필드를 읽으면 이벤트 공간에 복사한다. +**세는 반복과 BREAK.** LOOP는 낮음과 높음 사이의 값을 지역 칸에 두며 블록을 돌린다. 블록 안의 BREAK는 그 블록을 거기서 끝내고 +반복을 멈춘다(걷기도 같다). 안쪽 반복의 BREAK는 안쪽만 끝낸다. 바깥 걷기의 항목은 aup가 안쪽 반복 앞에서 인덱스 지역 칸에 담아 +읽는다. 바깥 걷기의 리스트는 안쪽에서 넣거나 지울 수 없으니 그 칸은 그 항목을 가리킨 채다. + **메시지의 행.** 행 필드는 가변 필드이고, 바이트는 그 행 목록의 저장 형식(항목마다 필드 순서대로 수는 binary64, text는 u32 길이와 바이트)이다. 메시지가 도착하면 핸들러가 돌기 전에 행 목록을 그 행들로 채우고, 유한하지 않은 수, UTF-8이 아닌 text, 끝이 맞지 않는 바이트는 메시지를 `limit`으로 실패시킨다. 행 목록은 모든 이벤트가 끝날 때(성공이든 실패든) 비워지고, diff --git a/docs/design/018-lifetimes-and-computation.md b/docs/design/018-lifetimes-and-computation.md index e25973c..1aad50f 100644 --- a/docs/design/018-lifetimes-and-computation.md +++ b/docs/design/018-lifetimes-and-computation.md @@ -117,10 +117,13 @@ view distance(from: u32, to: u32) = { # 보기의 본문(3단계): 스냅숏� "없음"은 없다. - LOOP는 **도는 대로** 센다(반복마다 블록 길이). `break`로 일찍 끝나는 반복이 쓰지 않을 몫으로 실패하지 않게 하려는 것이다. EACH와 FOLD는 지금처럼 시작할 때 항목 수 × 블록 길이를 센다. 곱은 넘치지 않게 센다(넘치면 예산을 넘은 것이다). -- **메모리는 자라는 대로 센다.** 이벤트가 리스트(저장되든 아니든, 이벤트의 리스트도)와 text에 더하는 바이트를 더할 때마다 - 센다. 예산이 있으면 이벤트가 시작할 때 가진 것 + 더한 것이 예산을 넘는 순간 `memory`로 실패한다(지금은 이벤트가 끝난 뒤에 - 본다). 예산이 없으면 한 이벤트가 더하는 것이 2^28 바이트(256 MiB)를 넘는 순간 실패한다. 그래서 고장 난 반복이 기기의 - 메모리를 다 쓰기 전에 멈춘다. +- **메모리는 자라는 대로 센다.** 이벤트가 리스트(저장되든 아니든, 이벤트의 리스트도), text, 보낼 것(outbox)에 더하는 바이트를 + 더할 때마다 센다(줄인 것은 뺀다). 두 가지로 센다. + - 저장 형식으로 더한 것이 메모리 예산을 넘는 순간 `memory`로 실패한다(예산이 있을 때). 이벤트가 끝난 뒤 상태가 예산을 넘는지는 + 지금처럼 따로 본다(답이 outbox의 보낸 것을 내보내는 것처럼 이벤트 안에서 잠시 넘었다가 돌아오는 일은 그대로 된다). + - 그것을 위해 가진 것 모두(리스트의 저장 기록과 되돌리기 기록까지)가 2^28 바이트(256 MiB, 예산이 더 크면 예산)를 넘는 순간 + `memory`로 실패한다. 예산이 없어도 그렇다. + 그래서 고장 난 반복은 기기의 메모리를 다 쓰기 전에 멈춘다. 리스트 하나의 항목 수 한도(2^24)가 먼저 올 수도 있다(`limit`). - 보기의 평가(3단계의 본문 포함)도 같은 실행량 예산과 같은 2^28 바이트(이벤트의 리스트)를 쓴다. ### 보기의 본문 (3단계) |
