diff options
Diffstat (limited to 'docs/design')
| -rw-r--r-- | docs/design/008-module-format.md | 16 | ||||
| -rw-r--r-- | docs/design/028-bytes-state.md | 22 |
2 files changed, 30 insertions, 8 deletions
diff --git a/docs/design/008-module-format.md b/docs/design/008-module-format.md index 41abb3b..8bfe285 100644 --- a/docs/design/008-module-format.md +++ b/docs/design/008-module-format.md @@ -82,7 +82,7 @@ v7은 027의 4단계(패턴 모으기)의 판이다. 4b로 **키별 문서**를 | 8 | u16 상태, u16 입력, u16 보기, u16 핸들러 | | 16 | u32 명령 수, u32 문자열 바이트 수 | | 24 | u16 필드, u16 상수, u16 레코드, u32 상수 블롭 바이트 수, u16 레코드 필드, u16 함수 | -| 38 | 상태 × 16 B: u32 이름, u32 타입(비트 0–7: 0 수, 1 text, 2 앵커(text나 리스트 안의 자리, 027의 4c), 3 리스트, 4 bool, 5 i64. 비트 8: 저장하지 않는 상태(transient, [018](018-lifetimes-and-computation.md)), 그 위는 0. 메시지의 행 목록은 transient가 아니고, transient text나 리스트를 가리키는 앵커는 transient다), 8 B 값: 수와 bool은 f64 초기값(bool은 0이나 1), i64는 초기값(부호 있는 little-endian), text는 u32 초기 상수, 앵커는 u32 대상(text나 리스트 상태)과 u32 플래그(text 안이면 1이 마크: 그 자리에 넣은 글 앞에 남는다. 리스트 안이면 0), 리스트는 u32 레코드와 u32 키(0이면 없음, 아니면 키 필드 + 1, 256이면 메시지의 행 목록: 이름은 그 필드의 경로 `입력.필드`이고 키가 없다) | +| 38 | 상태 × 16 B: u32 이름, u32 타입(비트 0–7: 0 수, 1 text, 2 앵커(text나 리스트 안의 자리, 027의 4c), 3 리스트, 4 bool, 5 i64, 6 바이트(028: text처럼 담고 UTF-8을 묻지 않는다, 그 안에 앵커는 없다). 비트 8: 저장하지 않는 상태(transient, [018](018-lifetimes-and-computation.md)), 그 위는 0. 메시지의 행 목록은 transient가 아니고, transient text나 리스트를 가리키는 앵커는 transient다), 8 B 값: 수와 bool은 f64 초기값(bool은 0이나 1), i64는 초기값(부호 있는 little-endian), text와 바이트는 u32 초기 상수, 앵커는 u32 대상(text나 리스트 상태)과 u32 플래그(text 안이면 1이 마크: 그 자리에 넣은 글 앞에 남는다. 리스트 안이면 0), 리스트는 u32 레코드와 u32 키(0이면 없음, 아니면 키 필드 + 1, 256이면 메시지의 행 목록: 이름은 그 필드의 경로 `입력.필드`이고 키가 없다) | | | 입력 × 16 B: u32 이름, u8 종류(1 메시지, 2 출력: 앱이 보내는 메시지, 모양은 메시지와 같고 핸들러가 없다, 3 인자: 한 보기가 받는 인자, 모양은 메시지와 같고 핸들러가 없으며 이름은 `보기.args`), u8 묶음(메시지의 것, 그 메시지를 만드는 것: 0 없음(호스트나 다른 앱이 보낸다), 1 키의 누름, 2 키의 뗌, 3 text 입력, 4 타이머, 5 frame, 6 가리킴), u16 0, u32 키 이름(누름·뗌)·주기(타이머, 1 ms–24시간을 ms로)·보기 번호(인자: 그 보기, 가리킴: 그 표) 또는 0, u16 첫 필드, u16 필드 수 | | | 필드 × 8 B: u32 이름(식별자, 또는 그룹 안의 필드면 점으로 이은 경로 `user.name`), u32 타입(1 u32le, 2 바이트, 3 수(binary64), 4 text, 5 행: 비트 8–23에 그 행이 채우는 행 목록 상태, 6 bool: 1바이트 0이나 1, 7 i64: 8바이트 부호 있는 little-endian). 페이로드는 접두부와 가변 필드의 바이트다. 접두부에는 선언 순서로 고정 필드의 값과 가변 필드(바이트·text)의 u32 길이가 들어가는데, 마지막 가변 필드는 길이 없이 나머지를 차지한다. 가변 필드의 바이트는 접두부 뒤에 선언 순서로 이어진다(가변 필드가 하나면 예전의 "바이트 꼬리"와 같다) | | | 상수 × 8 B: u32 블롭 오프셋, u32 길이 (UTF-8) | @@ -120,7 +120,7 @@ v7은 027의 4단계(패턴 모으기)의 판이다. 4b로 **키별 문서**를 | 24 | REPLY | b → | 이 메시지의 응답 | | 25 | REQUIRE | bool → | 거짓이면 이벤트가 `limit`으로 실패 | | 26 | TEXT_CONST | → t | 상수 `인자` | -| 27 | TEXT_LOAD | → t | text 상태 `인자`의 현재 값(복사 없는 버전) | +| 27 | TEXT_LOAD | → t 또는 b | text 상태 `인자`의 현재 값(복사 없는 버전). 바이트 상태(028)면 바이트 | | 28 | NUM_TEXT | n → t | 가장 짧은 왕복 10진수. 1e15 미만 정수는 소수점·지수 없이, −0은 `0`. `인자`의 비트 0–1이 1이면 bool → t: `true`·`false`, 2면 i64. 그 위는 형식([027](027-computation-core.md)): 비트 8–15 폭(왼쪽을 채움), 16 부호 뒤를 0으로 채움, 17–19 꼴(PureFormat: 10진, 16진, 대문자 16진, 2진, 8진, 고정 소수), 20–24 고정 소수나 10진의 소수점 뒤 자릿수 + 1(10진은 정수를 최소 단위로 보고 끝의 그 자릿수를 소수점 뒤에 쓴다: 2자리에서 1234는 `12.34`, −5는 `-0.05`, 돈의 센트. 027의 5단계). 정수의 꼴에 정수가 아닌 수는 `limit` | | 29 | CONCAT | t t → t 또는 b b → b | `인자` 1이면 바이트끼리 | | 30–32 | CHARS LINES TEXT_BYTES | t → n | 글자(Unicode scalar) 수, 줄 수(줄바꿈 + 1), 바이트 수 | @@ -131,7 +131,7 @@ v7은 027의 4단계(패턴 모으기)의 판이다. 4b로 **키별 문서**를 | 38 | TEXT_INSERT | c t → | text `인자`의 커서 위치에 넣는다 | | 39 | TEXT_REMOVE | c c → | 두 커서 사이를 지운다 | | 40 | TEXT_LINE | c → t | 커서가 있는 줄(줄바꿈 제외) | -| 41 | TEXT_SET | t → | text 전체를 바꾸고 그 text의 커서를 처음으로 | +| 41 | TEXT_SET | t 또는 b → | text 전체를 바꾸고 그 text의 커서를 처음으로. 바이트 상태(028)는 바이트를 받는다 | | 42 | TEXT_FROM | b → t | UTF-8이 아니면 이벤트가 실패(encoding) | | 43 | BYTES_FROM | t → b | 같은 바이트 | | 44 | ANCHOR_COUNT | a → n | 앵커 앞의 단위 수(`인자`는 MOVE와 같다): 글자 수, 0부터 센 줄, 0부터 센 항목의 자리 | @@ -360,7 +360,8 @@ frame 핸들러 없는 앱의 frame)은 보내지 않는다. 호스트는 앱을 새 기본값이 된다. 레코드가 같으면 리스트를 그대로 쓰고, 레코드가 바뀌었으면 항목마다 이름과 타입이 같은 필드(수·bool·i64는 위처럼)를 옮기고 새 필드는 기본값으로 채운다(키 있는 리스트는 그다음 키 순서로 놓인다). 커서와 인덱스는 대상 -text·리스트가 남을 때만 위치를 유지한다. +text·리스트가 남을 때만 위치를 유지한다. 이름이 같은 text와 바이트 상태(028)는 정확할 때만 서로 옮긴다: text는 언제나 바이트가 +되고, 바이트는 UTF-8일 때만 text가 되며 아니면 그 text의 초기값이다. 응답은 `pure_app_reply`로 순서대로 빌려준다. 페이로드를 복사하지 않는다. text 상태의 응답은 확정 전에 복사한다. text 보기는 `pure_app_view_text`로 빌려준다. @@ -394,9 +395,9 @@ ANCHOR_AT, ANCHOR_STORE)를 만든다. 그래서 인터페이스(Vega)는 앱 � | 상태 | 저장 형태 (런타임 이름공간) | |---|---| -| text | `text-이름`: UTF-8 바이트 그대로. 앱의 draft가 곧 저장 문서라 입력 한 글자는 바뀐 익스텐트만 추가한다 | +| text·바이트 | `text-이름`: 그 바이트 그대로(text는 UTF-8, 바이트 상태는 묻지 않는다, 028). 앱의 draft가 곧 저장 문서라 입력 한 글자는 바뀐 익스텐트만 추가한다 | | 리스트 | 이미지와 로그(아래). 트리에는 두지 않는다 | -| 수·bool·i64·커서·인덱스 | `values`: `PVS1`, 상태마다 종류·이름·8바이트(수는 binary64, bool은 0이나 1의 binary64, i64는 2의 보수, 리틀 엔디언). 바뀐 이벤트에서만 다시 쓴다 | +| 수·bool·i64·커서·인덱스 | `values`: `PVS1`, 상태마다 종류·이름·8바이트(수는 binary64, bool은 0이나 1의 binary64, i64는 2의 보수, 리틀 엔디언). 바이트 상태는 종류 7과 이름(8바이트는 0)으로 적힌다(028: UTF-8이 아닌 `text-이름`이 손상인지 바이트에서 옮긴 것인지 가른다). 바뀐 저장에서만 다시 쓴다 | - **리스트: 이미지와 로그.** 리스트는 저장소 디렉터리의 두 곳에 산다. **이미지** `image-이름`(파일 하나)은 `PLI1`, 레코드 필드 수, 필드마다 종류(0 수, 1 text, 2 바이트, 3 bool, 4 i64, 5 리스트)·이름(리스트는 그 뒤에 u8: 항목들의 레코드 번호), 리스트 @@ -427,7 +428,8 @@ ANCHOR_AT, ANCHOR_STORE)를 만든다. 그래서 인터페이스(Vega)는 앱 � 저장된 수·bool·i64 상태도 같은 규칙으로 새 모듈의 타입이 된다. 리스트 필드의 항목도 그래프의 레코드를 따라 같은 규칙으로 옮겨진다(3단계). 커서가 text 범위나 글자 경계를 벗어나거나, 인덱스가 리스트 밖이면 0이 된다. 깨진 리스트·text(형식 오류, UTF-8 - 아님)는 시작을 `store_error`로 멈춘다. 조용히 버리지 않는다. + 아님)는 시작을 `store_error`로 멈춘다. 조용히 버리지 않는다. 다만 UTF-8이 아닌 text의 이름을 `values`가 바이트 상태로 적고 + 있으면 타입이 바뀐 것이라 교체의 규칙대로 초기값이다(028). 바이트 상태는 UTF-8을 묻지 않는다. - **저장은 묶음이다.** 저장 한 번이 마지막 저장 이후 바뀐 상태들을 저장소의 **한 커밋**(`pure_draft_commit_all`)과 로그 항목 하나로 공개한다. 모두 보이거나 하나도 보이지 않는다. 저장이 실패하면 마지막 저장 이후의 이벤트가 **모두** 되돌려진다(값, text draft, 리스트 되돌리기 기록과 저널, 이벤트·tick 수). 그래서 diff --git a/docs/design/028-bytes-state.md b/docs/design/028-bytes-state.md index 9396105..7e760fa 100644 --- a/docs/design/028-bytes-state.md +++ b/docs/design/028-bytes-state.md @@ -1,6 +1,6 @@ # 028 — 바이트 하나인 상태 -작성일: 2026-10-19. 상태: 설계. [140](../research/140-spec-suite.md)의 "027 뒤의 결정점"에서 써서 닿은 명세가 둘(inflate, +작성일: 2026-10-19. 상태: 만들었다(아래 "만든 것"). [140](../research/140-spec-suite.md)의 "027 뒤의 결정점"에서 써서 닿은 명세가 둘(inflate, HTTP/1.1)이 된 틈이다. 쌓임을 막는 규칙(둘 이상의 명세)을 넘으므로 핵에 들인다. 같은 결정점의 다른 하나(바이트의 `==`)는 TEXT_COMPARE의 인자 비트로 이미 만들었다(008). @@ -75,3 +75,23 @@ TEXT_COMPARE의 인자 비트로 이미 만들었다(008). - **바꿀 결정.** bytes를 상태의 타입으로 들인다. - **최소 확인.** 위 검증 모두. - **중단 기준.** 실행기만의 길이나 묶음 실행기의 명령 수가 1%를 넘게 바뀌면 멈추고 어디를 건드렸는지 찾는다. + +## 만든 것 (2026-10-19) + +- **Pure.** 상태 타입 6을 text 상태로 읽고 `state_flags`에 `PURE_TEXT_BYTES`를 둔다. 표시가 상태의 모양에 들어가므로, 질의 모듈과 + 교체를 받아들이는 serve의 견주기(`same_states`)가 그것까지 견준다. 검증: bytes 상태의 TEXT_LOAD는 바이트를 놓고 TEXT_SET은 + 바이트를 받는다. 커서의 명령(CUR_START, CUR_END, TEXT_INSERT, TEXT_REMOVE, TEXT_LINE, 앵커의 MOVE·COUNT·AT)은 거절하고("anchor in + bytes"), 앵커가 bytes 상태를 가리키면 로드가 거절한다. 저장: `values`에 종류 7과 이름을 적는다. text 상태의 파일이 UTF-8이 + 아닐 때 그 표시가 있으면 초기값, 없으면 `store_error`다. 교체: bytes → text는 draft가 UTF-8일 때만 남기고, 아니면 초기값으로 + 저장소의 draft를 다시 연다. pure-run은 16진으로 보인다. +- **aup.** `state x: bytes`(`= "..."`), 이름은 바이트 값, `x = …`는 바이트(문자열은 바이트를 만난다), 커서와 text 연산은 진단. +- **검증.** + - 단위 시험 `bytes_states`: 저장소에서 다시 시작하는 일곱 번, 실행 중의 교체 셋, 거절 넷. 0xff와 0x00이 다시 시작을 지나 남는다. + bytes → text → bytes → text를 오가며 UTF-8이 아닌 것은 초기값, UTF-8인 것은 그대로다. 표시 없이 UTF-8이 아닌 text 파일은 기존 + 시험대로 여전히 `store_error`다. + - aup의 `bytes_state`: 300걸음을 저장소로 15번 다시 시작하며 파이썬과 같다. 같은 이름의 text로 저장소에서 시작하고 실행 중에 + 교체한다. 진단 셋. + - Pure, Vega, aup의 전체 검사가 지난다. + - 명령 수(b47 대 b46): 묶음의 BFS +0.12%, 나머지 ±0.001% 안이다. 실행기의 걸음은 그대로다(로드와 저장만 바뀌었다). + - 은행 질의(s45와 s47을 한 번에 번갈아 여섯 번의 중앙값, 바이트의 비교와 함께): in_credit −0.31%, per_branch −0.18%, ranks + −0.11%, 나머지 ±0.01% 안이다. 일곱 질의의 답은 바이트까지 같다. |
