aboutsummaryrefslogtreecommitdiffstats
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/design/008-module-format.md72
1 files changed, 72 insertions, 0 deletions
diff --git a/docs/design/008-module-format.md b/docs/design/008-module-format.md
new file mode 100644
index 0000000..616125c
--- /dev/null
+++ b/docs/design/008-module-format.md
@@ -0,0 +1,72 @@
+# Pure 모듈 형식 v1
+
+2026-09-25. 상태: scalar 모듈 확정, 구현 `prototypes/connections/module.{h,c}`.
+
+Pure가 실행하는 앱 정의의 형식이다. JVM이 class 파일 형식을 소유하듯 Pure가 이 형식과
+검증 규칙을 소유한다. 생산자는 [aup](/srv/git/aup.git) 같은 툴체인이다. Pure는 소스·문법을 모르며,
+로드할 때 모든 규칙을 확인한 모듈만 실행한다.
+
+v1은 워크벤치 scalar 앱과 같은 의미를 담는다. f64 상태, 키 입력, 원자적 이벤트 핸들러,
+순수한 보기다. 바이트 값과 영속 문서는 v2에서 추가한다.
+
+## 바이트 배치
+
+모든 정수는 little-endian이고, 실수는 IEEE binary64 비트 그대로다.
+
+| 위치 | 내용 |
+|---|---|
+| 0 | `PUREMOD1` (8 B) |
+| 8 | u16 상태 수, u16 입력 수, u16 보기 수, u16 핸들러 수 |
+| 16 | u32 명령 수, u32 문자열 바이트 수 |
+| 24 | u32 0, u32 0 (예약) |
+| 32 | 상태 × 16 B: u32 이름, u32 0, f64 초기값 |
+| | 입력 × 12 B: u32 이름, u32 종류(1 = 키), u32 키 이름 |
+| | 보기 × 12 B: u32 이름, u32 시작 명령, u32 명령 수 |
+| | 핸들러 × 12 B: u32 이벤트, u32 시작 명령, u32 명령 수 |
+| | 명령 × 16 B: u8 opcode, 0 3바이트, u32 인자, f64 값 |
+| | 문자열: `[u8 길이][바이트]`의 연속. 이름은 이 영역의 오프셋이다 |
+
+파일 크기는 위 합과 정확히 같아야 한다. 이벤트 번호는 `frame`이 0, 입력 `i`의 누름이 `1 + 2i`,
+뗌이 `2 + 2i`다. 핸들러는 파일 순서대로 실행한다.
+
+## 명령
+
+| opcode | 이름 | 스택 | 의미 |
+|---:|---|---|---|
+| 0 | CONST | → v | 값(유한)을 넣는다 |
+| 1 | LOAD | → v | 상태 `인자`를 읽는다 |
+| 2 | DT | → v | 이벤트 시간(frame 1/60, 입력 0). 핸들러 전용 |
+| 3–6 | ADD SUB MUL DIV | a b → v | DIV에서 b = 0이면 실패 |
+| 7 | NEG | a → v | |
+| 8–13 | LT LE GT GE EQ NE | a b → 0/1 | |
+| 14–16 | AND OR NOT | | 0이 아니면 참, 양쪽 모두 계산 |
+| 17–18 | MIN MAX | a b → v | IEEE 754-2019: −0 < +0 |
+| 19 | CLAMP | x lo hi → v | lo > hi이면 실패 |
+| 20 | STORE | v → | 상태 `인자`에 쓴다. 핸들러 전용 |
+| 21 | JZ | c → | c = 0이면 `인자`로. 핸들러 전용 |
+| 22 | JMP | | `인자`로. 핸들러 전용 |
+
+연산 결과가 유한하지 않으면 실패한다. 실패하면 그 이벤트의 모든 핸들러가 한 일이 취소된다.
+
+## 로드할 때 검증하는 것
+
+- 머리말, 예약 바이트, 명령 패딩이 0인지. 한도(상태 32, 입력 8, 보기 24, 핸들러 64, 명령 512,
+ 문자열 32 KiB)와 정확한 파일 크기.
+- 이름은 ASCII 식별자 1–31바이트. 상태·입력·보기 이름은 한 이름공간에서 겹치지 않는다.
+ 키는 `Space Enter ArrowLeft ArrowRight ArrowUp ArrowDown KeyA–KeyZ Digit0–Digit9` 중 하나이고 겹치지 않는다.
+- 초기값과 CONST 값은 유한하다. 인자·값을 쓰지 않는 명령은 둘 다 0이다(표현이 하나뿐).
+- 보기·핸들러의 명령 범위가 모듈 안에 있고, 핸들러 이벤트가 존재한다.
+- 각 블록에서: 모든 명령이 도달 가능하고, 분기는 블록 안에서 앞으로만 간다.
+ 모든 경로가 합류점에서 같은 스택 높이를 갖고, 높이는 0–64다. 핸들러는 0개, 보기는 1개의 값을 남긴다.
+ 보기에는 DT, STORE, 분기가 없다.
+
+분기가 앞으로만 가므로 한 번의 순차 검사로 모든 들어오는 경로를 본다. 검증된 모듈을 실행할 때는
+스택 검사가 필요 없고, 이벤트 하나의 실행량은 핸들러 명령 수 이하다.
+
+## 실행 인스턴스
+
+`PureApp`은 모듈 참조와 상태 값(최대 32 × f64)만 가진다(288 B). 이벤트는 상태 사본에서 실행하고
+모두 성공했을 때만 반영한다. `pure_app_replace`는 같은 이름의 상태 값을 유지하고 새 상태에 초기값을 준다.
+불러오기·실행·교체 모두 할당하지 않는다. `PureModule`은 고정 용량 11,728 B이다.
+
+아직 런타임 코어(`runtime.c`)의 작업·예산 모델과 연결하지 않았다. 호스트가 직접 호출한다.