diff options
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/design/008-module-format.md | 22 | ||||
| -rw-r--r-- | docs/design/027-computation-core.md | 46 |
2 files changed, 60 insertions, 8 deletions
diff --git a/docs/design/008-module-format.md b/docs/design/008-module-format.md index 61e053b..f67cc37 100644 --- a/docs/design/008-module-format.md +++ b/docs/design/008-module-format.md @@ -34,7 +34,9 @@ v7은 027의 4단계(패턴 모으기)의 판이다. 4b로 **키별 문서**를 상태 종류 2가 text나 리스트 안의 자리이고(bool은 4, i64는 5), 명령 일곱(ANCHOR_*)이 커서와 인덱스의 열셋을 대신한다. 로드가 그것을 대상에 맞는 런타임의 명령으로 바꿔 쓴다(module-run.h). 4d로 **장치의 사건이 메시지**가 되었다: 입력의 종류는 메시지, 출력, 인자 셋이고, 키의 누름과 뗌, text 입력, 타이머, frame, 가리킴은 메시지 입력의 묶음(무엇이 그 메시지를 만드는가)이다. 핸들러의 -이벤트는 그 입력의 번호이고, DT와 TEXT_INPUT은 필드 읽기(FIELD)가 대신한다(아래 표의 번호가 당겨졌다). 4단계가 끝날 때까지 v7은 걸음마다 바뀐다(1.0 전, 생산자는 aup 하나다). +이벤트는 그 입력의 번호이고, DT와 TEXT_INPUT은 필드 읽기(FIELD)가 대신한다(아래 표의 번호가 당겨졌다). 4e로 **보기가 아무 값**이 되었다: 보기와 열의 타입이 +레코드 필드의 것(바이트와 리스트가 더해졌다)이고, 표는 리스트 보기다. 리스트 보기는 리스트 상태 그대로나 그 지도, 또는 블록이 +낸 리스트를 행으로 가지며, 보기 항목은 20바이트다. 4단계가 끝날 때까지 v7은 걸음마다 바뀐다(1.0 전, 생산자는 aup 하나다). **레코드 안의 리스트**(027의 2b). - 레코드 필드의 타입 4(LIST)는 항목들의 레코드를 기본값 자리(i64)에 둔다. @@ -86,7 +88,7 @@ v7은 027의 4단계(패턴 모으기)의 판이다. 4b로 **키별 문서**를 | | 상수 × 8 B: u32 블롭 오프셋, u32 길이 (UTF-8) | | | 레코드 × 8 B: u32 이름, u16 첫 레코드 필드, u16 필드 수(1–16) | | | 레코드 필드 × 16 B: u32 이름, u32 타입(0 수, 1 text, 2 bool, 3 i64, 4 리스트, 5 바이트), 8 B 기본값: 수와 bool은 f64(bool은 0이나 1), i64는 정수, text와 바이트는 u32 상수, 리스트는 항목들의 레코드 | -| | 보기 × 16 B: u32 이름, u8 타입(0 수, 1 text, 2 표, 3 bool, 4 i64), u8 걸러진 표의 리스트 상태 + 1(그 밖에는 0), u16 표(열이면 그 표 보기 + 1, 아니면 0), u32 시작 명령, u32 명령 수. 표는 시작 명령 자리에 리스트 상태, 명령 수 0. 걸러진 표는 타입 다음 바이트에 리스트 상태 + 1, 시작·명령 수에 필터 블록 | +| | 보기 × 20 B: u32 이름, u8 타입(레코드 필드의 것, 027의 4e: 0 수, 1 text, 2 bool, 3 i64, 4 리스트, 5 바이트), u8 0, u16 표(열이면 그 리스트 보기 + 1, 아니면 0), u16 레코드 + 1(리스트 보기와 리스트 열의 항목의 레코드, 지도는 0), u16 리스트 상태 + 1(상태 위의 리스트 보기, 그 밖에는 0), u32 시작 명령, u32 명령 수. 상태 위의 리스트 보기는 블록이 필터(없으면 0)이고, 레코드가 그 상태의 것이면 그 필드가 열이다(로드가 짓는다). 레코드가 0인 지도는 뒤따르는 열들이 행의 필드다. 상태가 없는 리스트 보기는 블록이 제 레코드의 리스트를 남긴다 | | | 핸들러 × 12 B: u32 이벤트, u32 시작 명령, u32 명령 수 | | | 함수 × 12 B: u32 시작 명령, u32 명령 수, u8 매개변수 수, u8 결과 수, u16 0 | | | 서명 항목 × 4 B: 함수마다 매개변수, 그다음 결과의 차례로. u8 타입(레코드 필드의 타입: 0 수, 1 text, 2 bool, 3 i64, 4 리스트, 5 바이트), u8 0, u16 리스트의 레코드(그 밖에는 0) | @@ -238,8 +240,9 @@ bool은 실행 중에 수의 칸에 든 0이나 1이고, i64는 같은 8바이� - 인자(종류 6)는 열이 아닌 보기 하나를 가리키고, 보기마다 하나이며, 이름이 `보기 이름.args`다. 핸들러를 갖지 않는다. 그 보기와(표라면 그 열과 필터도) 그 안의 집계는 FIELD로 인자를 읽는다. 집계 블록은 둘레 블록의 메시지나 인자를 읽을 수 있다 (읽기뿐: 응답은 핸들러 자신의 코드에만 있다). -- 표는 리스트 상태를 가리키고 열은 앞에 나온 표를 가리킨다. 표 밖의 이름은 한 이름공간이고, 열 이름은 표 - 안에서만 유일하다. +- 리스트 보기는 리스트 상태를 가리키거나(그 레코드이거나 지도) 블록이 리스트를 낸다(레코드가 있다). 열은 앞에 나온 지도를 + 가리키고, 리스트 열은 항목의 레코드를 적는다. 레코드의 리스트 보기는 열을 갖지 않는다(필드가 열이다). 보기 밖의 이름은 한 + 이름공간이고, 열 이름은 리스트 보기 안에서만 유일하다. 지은 열까지 보기는 64개다. - 반복(LOOP, EACH)은 제 피연산자 말고는 빈 스택에서 연다. 반복의 블록은 그 실행의 스택 바닥에서 시작하므로, 아래에 값을 둔 반복은 스택의 64칸을 넘을 수 있었다(검증을 지난 모듈이 실행기를 죽였다. 2c에서 찾아 막았다). - 함수(2c): 블록은 매개변수를 스택에 두고 시작하고, 모든 길이 RETURN으로 끝난다. RETURN은 자기 함수의 결과 타입을 맨 위에서 @@ -361,8 +364,11 @@ text·리스트가 남을 때만 위치를 유지한다. ANCHOR_AT, ANCHOR_STORE)를 만든다. 그래서 인터페이스(Vega)는 앱 코드 없이 목록의 클릭을 포커스로 옮긴다. 4d 전에는 핸들러 없는 이벤트(`pure_app_point`)였고, 옮길 인덱스를 보기에서 찾았다(`pure_module_position`). -표 보기는 리스트 항목마다 행 하나를 가진다(`pure_app_rows`). 걸러진 표는 필터 블록이 참을 남긴 항목마다 -행 하나를 가진다(항목 순서 그대로). 필터는 상태가 바뀐 뒤 처음 행을 물을 때 항목마다 한 번 돌고, 그 결과(행 → 항목)를 +리스트 보기는 리스트 항목마다 행 하나를 가진다(`pure_app_rows`). 걸러진 리스트 보기는 필터 블록이 참을 남긴 항목마다 +행 하나를 가진다(항목 순서 그대로). 블록이 리스트를 내는 보기(027의 4e)는 바뀜 뒤 처음 물을 때 블록을 한 번 돌고, 그 리스트를 +저장 형태의 리스트로 옮겨 다음 바뀜까지 행과 칸에 쓴다. 레코드의 필드인 열은 계산 없이 항목의 필드를 읽는다. 리스트의 칸은 +그 항목들을 3단계의 저장 형태로 빌려주고(`pure_app_cell_items`), `pure_items_next`가 항목 하나의 칸들을 읽는다. 바이트의 +보기와 칸은 text처럼 빌려준다(`pure_app_view_text`, `pure_app_cell_text`). 필터는 상태가 바뀐 뒤 처음 행을 물을 때 항목마다 한 번 돌고, 그 결과(행 → 항목)를 다음 변경까지 쓴다. 칸마다 다시 거르지 않는다. 변경 번호는 이벤트, 가리키기, 저장 실패의 되돌리기, 모듈 교체마다 오르고 되돌아가지 않는다. 열의 `ROW`는 행이 아니라 항목이다. 호스트는 `pure_app_row_item`·`pure_app_item_row`로 행과 항목을 오간다. 그래서 포커스(인덱스, 곧 항목)를 걸러진 목록의 행으로 보이고, 클릭한 행을 항목으로 가리킨다. 호스트는 보여 줄 칸만 @@ -477,8 +483,8 @@ ANCHOR_AT, ANCHOR_STORE)를 만든다. 그래서 인터페이스(Vega)는 앱 � | 요청 | 뜻 | |---|---| -| `GET /views/이름` | 보기의 값. 수는 가장 짧은 왕복 10진수, bool은 `true`·`false`, text는 UTF-8 그대로(`text/plain`). text 상태를 그대로 보이는 보기(`view page = note`)는 저장된 익스텐트를 빌려준다([079](../research/079-lent-views.md)) | -| `GET /views/표?from=N&count=M` | 표의 행: `{"rows":전체,"from":N,"items":[{열: 값}…]}`(`application/json`, bool 열은 `true`·`false`). 요청한 행의 칸만 계산한다. 값이 없는 칸은 `null` | +| `GET /views/이름` | 보기의 값. 수는 가장 짧은 왕복 10진수, bool은 `true`·`false`, text는 UTF-8 그대로(`text/plain`), 바이트는 그대로(`application/octet-stream`). text 상태를 그대로 보이는 보기(`view page = note`)는 저장된 익스텐트를 빌려준다([079](../research/079-lent-views.md)) | +| `GET /views/표?from=N&count=M` | 리스트 보기의 행: `{"rows":전체,"from":N,"items":[{열: 값}…]}`(`application/json`, bool 열은 `true`·`false`, 바이트는 16진 문자열, 리스트는 그 레코드의 필드를 가진 객체의 배열). 요청한 행의 칸만 계산한다. 값이 없는 칸은 `null` | | `GET /views/이름?인자=값…` | 인자를 받는 보기(표라면 `from`·`count`와 함께). 값은 `%XX`를 풀어 읽고, 고정 필드는 메시지의 쿼리 필드와 같다. 빠진 고정 인자, 모르는 이름, 두 번 준 인자, 타입이 다른 값은 400 `invalid`. 등록한 질의도 같다(`GET /queries/이름?인자=값`) | | `POST /inputs/이름` | 이벤트. text 입력은 본문이 text, 키의 누름은 누름 뒤 같은 키의 뗌(받는 입력이 있으면). 타이머·frame·가리킴과 출력·인자에는 `no_input`. 메시지는 고정 필드(u32, 수, bool)를 쿼리(`?points=3`, `?done=true`, 그룹 안이면 `?to.zip=7`)로, 가변 필드 하나를 본문으로 받거나, `Content-Type: application/json` 본문의 객체로 필드를 받는다(문자열은 바이트·text, 수는 u32·수, `true`·`false`는 bool, 그룹은 안의 객체). 응답 본문은 핸들러의 `reply`(메시지 필드) | | `POST /inputs/이름` + `X-Pure-Source`·`X-Pure-Sequence` | 다른 앱의 출력에서 전해진 메시지(`pure_app_deliver`): 번호마다 한 번 적용하고, 이미 들은 번호는 200. 답에 `X-Pure-Batch: 256`을 싣고, `X-Pure-Count: N`이면 본문은 N개 객체의 JSON 배열(연속 번호, 한 묶음에서 차례로 적용) | diff --git a/docs/design/027-computation-core.md b/docs/design/027-computation-core.md index eeebd8b..16cb149 100644 --- a/docs/design/027-computation-core.md +++ b/docs/design/027-computation-core.md @@ -364,6 +364,52 @@ - **4e. 보기는 아무 값(의심 2).** - 보기의 타입은 레코드 필드의 타입이다. 표는 레코드의 리스트를 내는 보기이고, 열은 그 레코드의 필드다. - 게으른 칸 계산과 한 번 훑는 집계는 그 구현으로 남는다. 항목이 리스트를 담을 수 있고, 보기의 본문이 지은 리스트도 낼 수 있다. + - **설계(2026-10-18).** + - 타입: 보기와 열의 타입은 레코드 필드의 번호를 쓴다(0 수, 1 text, 2 bool, 3 i64, 4 리스트, 5 바이트). 표(2)는 리스트가 + 되고, 바이트의 보기와 열이 새로 생긴다. 레코드 필드, 함수 서명, 보기가 한 타입 표를 쓴다. + - 리스트 보기의 행은 한 리스트의 항목이다. 세 가지로 짓는다: + - 상태 리스트 그대로(걸러질 수 있다): `view all = tasks`, `view open = each t in tasks where !t.done`. 열은 그 레코드의 + 필드다. + - 상태 리스트의 지도: `each t in tasks where … { 열: 식 }`. 열의 블록이 행마다 계산한다(지금의 표, 게으르게). + - 본문이나 식이 낸 리스트: `view top { let xs: list of R … return xs }`. 본문은 바뀜마다 한 번 돌고, 그 리스트를 다음 + 바뀜까지 행과 칸에 쓴다(걸러진 표의 행처럼). 열은 R의 필드다. + - 형식: 보기 항목이 20바이트가 된다. u32 이름, u8 타입, u8 0, u16 표 + 1(열), u16 레코드 + 1(리스트의 항목의 레코드: 그대로와 + 본문, 리스트 열. 지도는 0이고 열들이 행의 필드다), u16 리스트 상태 + 1(상태 위의 리스트 보기), u32 시작, u32 수. 그대로인 + 리스트 보기의 열은 로드가 필드마다 짓는다(이름과 타입이 필드의 것이고, 칸은 항목의 필드를 계산 없이 읽는다). + - 항목이 리스트를 담는다: 리스트 타입의 칸은 그 리스트를 3단계의 저장 형태로 빌려준다(`pure_app_cell_items`). + `pure_items_next`가 그 형태에서 항목 하나의 칸들을 읽는다. pure-run과 serve의 JSON은 객체의 배열로 쓰고, Vega는 항목 수를 보인다. + - 바이트: pure-run과 JSON은 16진 문자열로 쓴다. serve의 바이트 보기는 `application/octet-stream`이다. Vega는 16진으로 보인다. + - 가리킴은 상태 위의 리스트 보기만 받는다(옮길 인덱스가 그 상태의 것). + - 4e에 넣지 않는 것: 리스트를 담은 레코드의, 본문이 지은 리스트(그 안의 리스트가 그 평가의 것이라 빌려줄 수 없다). 거절한다. + - aup: `view x = 리스트 식`(상태 이름이나 값), `each … where …`의 `{ }` 없는 꼴, 본문의 `return 리스트`, 바이트의 보기와 열, + 리스트의 열(`{ tags: t.tags }`)을 받는다. + - **만듦(2026-10-18).** 모듈 형식 v7. + - 형식: 보기 항목이 20바이트다(위). 보기의 타입은 레코드 필드의 번호이고, `PURE_VIEW_TABLE`이 `PURE_VIEW_LIST`가 되었다. + 전의 표 없는(걸러지지 않은) 꼴이 상태를 시작 명령 자리에 적던 것도 없어졌다(상태는 늘 제 자리에). + - 로드: 레코드의 리스트 보기(상태 그대로, 블록이 낸 것)에 필드마다 열을 짓는다(`view_field`: 계산 없이 항목의 필드를 읽는다). + 검증기는 리스트를 내는 블록이 그 레코드의 리스트 하나를 남기는지 본다. 가리킴은 상태 위의 리스트 보기만 받는다. + - 런타임: 블록이 낸 리스트는 걸러진 행의 자리(`struct PureRows`)에 저장 형태의 리스트로 옮겨 두고 바뀜마다 다시 짓는다. + 리스트의 칸은 저장 형태로 빌려준다(`pure_app_cell_items`, 지도의 리스트 열은 평가가 낸 리스트를 그 형태로 쓴다). + `pure_items_next`가 그 형태를 읽는다(pure-run의 읽기도 그것으로 바꿨다). + - 고친 것: 본문 없는 보기의 평가가 늘어날 몫(`room`)을 새로 잡지 않아, 스냅숏의 reader(serve의 보기)에서 저장 리스트 안의 + 리스트를 읽으면 `memory`로 값이 없었다. 이제 그것을 읽는 보기와 열(KEPT_GET이 있는)은 로드가 본문으로 표시해 평가마다 잡는다. + 4e 전에는 그런 보기를 짓는 길이 없었다(리스트 값은 본문 안에서만). + - 잰 것이 바꾼 것: 첫 빌드(s36)는 은행의 걸러진 표 질의가 field +5.9%, found +3.8%, large +3.1%였다. `view_of`가 부르는 곳이 + 일곱이 되며 인라인에서 빠졌고(그 함수가 따로 5.9%), serve의 `put_bytes`도 인라인 결정이 바뀌었다. `view_of`를 늘 인라인하고, + 지은 열의 길(`field_of`)과 계산된 리스트(`computed`)와 serve의 새 쓰기(`put_items`, `put_hex`)를 따로 두고, 평가마다 몫을 + 잡던 것을 위의 표시로 바꾸고, 계산된 리스트의 행을 걸러진 행처럼 두어 행 찾기의 가지를 뺐다. + - 호스트: pure-run은 바이트를 16진, 리스트 칸을 객체의 배열로 쓴다. serve는 바이트 보기를 `application/octet-stream`으로, + JSON 안의 바이트를 16진 문자열로, 리스트 칸을 객체의 배열로 쓴다. Vega는 바이트를 16진, 리스트 칸을 항목 수(`2 items`)로 보인다. + - aup: 위의 꼴을 받는다. 상태의 리스트를 본문이 돌려주면 `view all = items`로 쓰라고 말한다(LIST_VALUE는 이벤트의 리스트만). + - 시험: 단위 시험 `list_views`(그대로, 걸러짐, 블록이 낸 리스트, 지도의 리스트와 바이트 열, 바이트 보기, 거절 여섯). aup의 + `stored_nested`가 보드의 리스트 보기 넷(그대로, 걸러짐, 리스트와 바이트 열의 지도, 본문이 지은 리스트)을 모델과 메모리와 + 재시작하는 저장소에서 대조한다. Pure의 `server_trees`가 저장한 숲을 HTTP의 리스트 보기(중첩 배열, 16진 바이트)와 바이트 보기로 + 모델과 대조한다(재시작 뒤에도). Vega의 `lists_and_bytes`가 CLI, TUI, 말, 웹에서 리스트 칸과 바이트를 본다. + - 남은 것: 필터 안에서 리스트 필드의 수를 읽는 것(`col.cards.count`: aup가 레지스터에 묶는데, 필터는 효과가 없어야 한다). + - 명령 수(b37 대 b35): 묶음과 함께, 실행기만 모두 ±0.001% 안이다. 은행 질의(s35는 4d의 aup 모듈, s37은 4e의 것, 번갈아 각 + 여섯 번의 중앙값)는 field +0.67%, found +0.43%, large +0.31%, in_credit −0.20%, per_branch −0.11%, ranks −0.05%, none 0.00%다. + - 줄 수: 코어 22,221 → 22,383, serve.c 4,978 → 5,031, aup의 compile.c 5,679 → 5,713. 4e는 지운 것보다 더한 것(계산된 리스트, + 리스트 칸, 바이트)이 많다. 타입 표 하나가 모아진 것이 줄어든 것이다. - **4f. 고정 한도를 뺀다(의심 7).** - 상태, 입력, 레코드, 필드, 중첩의 수를 모듈에 맞춰 잡는다. 비트 하나씩 쓰던 집합은 길이를 가진다. - aup 소스의 32 KB도 뺀다. |
