diff options
| author | eunhhu <[email protected]> | 2026-09-25 10:55:38 +0100 |
|---|---|---|
| committer | eunhhu <[email protected]> | 2026-09-25 10:55:38 +0100 |
| commit | e058795152fdb678aa71b67acd7a0fb44dabe747 (patch) | |
| tree | 68345933728187e18f5de6522119f6abba433a99 /docs/design/001-language-v0.md | |
| download | aup-e058795152fdb678aa71b67acd7a0fb44dabe747.tar.gz aup-e058795152fdb678aa71b67acd7a0fb44dabe747.zip | |
Charter aup and specify language v0
aup is the language and toolchain for the Pure runtime, as Java and javac
are for the JVM. v0a unifies the workbench scalar dialect (state, key
inputs, atomic handlers, views) with the same numeric semantics; v0b drafts
byte values and runtime-owned persistent documents to replace the document
dialect. Parity with the existing executors is the acceptance test.
Diffstat (limited to 'docs/design/001-language-v0.md')
| -rw-r--r-- | docs/design/001-language-v0.md | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/docs/design/001-language-v0.md b/docs/design/001-language-v0.md new file mode 100644 index 0000000..e690a89 --- /dev/null +++ b/docs/design/001-language-v0.md @@ -0,0 +1,110 @@ +# aup v0 — 한 언어, 한 모듈 형식 + +2026-09-25. 상태: v0a(scalar) 확정, v0b(바이트·영속 문서) 초안. + +착수 기준: + +- 바꿀 결정: Pure 앱을 두 `.pure` 방언과 두 실행기(워크벤치 Zig scalar VM, 문서 `PureProgram` 해석기)로 + 계속 만들지, aup 한 언어 → Pure 모듈 한 형식 → Pure 실행기 하나로 합칠지. +- 남은 질문: 작은 언어 하나와 형식 하나로 두 앱의 관찰 가능한 동작을 특수 규칙 없이 표현할 수 있는가? + 런타임은 소스를 몰라도 로드 전에 모듈을 검증할 수 있는가? +- 최소 확인: v0a는 워크벤치 예제를 aup로 옮겨, 같은 이벤트열에서 Pure 실행기의 상태가 워크벤치 + Zig 엔진과 비트 단위로 같아야 한다. v0b는 문서 편집 앱을 옮겨 기존 CLI와 저장 결과가 같아야 한다. +- 중단 기준: 한쪽 앱에 그 앱만을 위한 규칙이 필요하거나, Pure 실행기가 기존 두 실행기의 합보다 + 커지면 설계를 다시 본다. + +## 의심한 관례와 aup의 선택 + +| 관례 | aup | +|---|---| +| 앱이 저장·불러오기·직렬화 코드를 쓴다 | 상태를 선언하면 런타임이 소유한다(영속화는 v0b) | +| 트랜잭션과 롤백을 앱이 관리한다 | 모든 이벤트가 트랜잭션이다. 성공하면 반영하고, 실패하면 아무것도 바뀌지 않는다 | +| 요청/응답 핸들러와 라우터 | 입력은 이름 있는 이벤트다. 키·CLI·HTTP는 호스트 어댑터가 입력으로 바꾼다 | +| 화면용 모델을 따로 만든다 | `view`는 상태의 순수 함수다. 호스트와 나중의 Vega가 읽어 표시한다 | +| 런타임이 소스를 해석한다 | 툴체인이 모듈로 컴파일하고, 런타임은 검증한 뒤 실행한다(JVM의 class 파일처럼) | +| 이벤트 처리 시간에 상한이 없다 | 반복이 없고 분기는 앞으로만 한다. 이벤트당 실행량의 상한이 모듈에서 정해진다 | + +## v0a 문법 + +```text +# 주석은 줄 끝까지 +state count = 0 # f64 상태. 초기값은 부호 있는 숫자 상수 +input tap = key Space # 키 입력. tap.down, tap.up 이벤트 +view label = count # 상태의 순수 함수 +view width = 40 + min(count, 20) * 8 + +on tap.down { + count = count + 1 +} + +on frame { # 1/60초 진행. 핸들러 안에서 dt를 쓸 수 있다 + if count > 20 { + count = 0 + } else { + count = count + dt + } +} +``` + +- 선언과 문장은 줄바꿈이나 `;`로 끝난다. 이름은 ASCII `[A-Za-z_][A-Za-z_0-9]*`, 31바이트 이하다. +- 예약어: `state input view on if else key frame dt min max clamp`. +- 키: `Space Enter ArrowLeft ArrowRight ArrowUp ArrowDown KeyA..KeyZ Digit0..Digit9`. 입력 이름과 + 키는 각각 한 번만 쓴다. 상태·입력·보기의 이름공간은 서로 겹칠 수 없다. +- 식: 숫자, 상태 이름, `dt`(핸들러 안에서만), 괄호, 단항 `- !`, 이항 `* /`, `+ -`, + `< <= > >=`, `== !=`, `&&`, `||`(뒤로 갈수록 우선순위가 낮다), `min(a,b) max(a,b) clamp(x,lo,hi)`. +- 문장: `이름 = 식`, `if 식 { … }`, `if 식 { … } else { … }`. +- 같은 이벤트의 핸들러가 여럿이면 소스 순서로 하나의 이벤트 안에서 실행한다. + +## 의미 (워크벤치 엔진과 같음) + +- 값은 IEEE binary64다. 연산 결과나 읽은 값이 유한하지 않으면, 0으로 나누면, `clamp`의 `lo > hi`이면 + 이벤트 전체가 실패하고 상태는 이벤트 전과 같다. +- 비교와 논리 연산은 0 또는 1을 낸다. `&& ||`는 양쪽을 모두 계산한다. 0이 아니면 참이다. +- `if`의 조건은 한 번 계산한다. 문장은 순서대로 실행한다. +- `frame`의 `dt`는 1/60이고 키 이벤트의 `dt`는 0이다. +- 한도: 상태 32, 입력 8, 보기 24, 핸들러 64, 명령 512, 스택 64, 소스 32 KiB. +- 모듈을 교체하면 같은 이름의 상태 값은 유지하고, 새 상태는 초기값을 쓰고, 없어진 상태는 버린다. + 교체에 실패하면 이전 모듈과 상태가 그대로다. + +워크벤치와 다른 점은 셋이다. 입력 종류를 `key`로 적고, 도형 대신 `view`로 값을 내보내고, `else`가 있다. +도형과 인터페이스 표현은 Vega가 맡는다. 포인터 입력, 값 입력, 레코드·규칙은 v0a에 없다. + +## 모듈 + +모듈 형식은 Pure가 소유한다([Pure 설계 008](/srv/git/pure.git): `docs/design/008-module-format.md`). +aup는 그 형식의 생산자일 뿐이다. 모듈에는 이름표·초기값·입력 키·보기·핸들러·명령이 들어가고, +Pure는 로드할 때 범위·이름·분기·스택 높이를 모두 정적으로 검증한다. 검증을 통과한 모듈은 실행 중에 +스택 넘침이나 잘못된 참조를 만들 수 없다. + +## 툴체인 + +- `aup check FILE`: 진단만 한다. 오류는 `파일:줄:열: 메시지` 한 줄이다. +- `aup build FILE -o OUT.pmod`: 모듈을 만든다. 같은 소스는 바이트 단위로 같은 모듈을 만든다. +- C17, 외부 의존성 없음. 컴파일러는 Pure를 링크하지 않는다. 시험에서는 Pure의 검증기로 결과를 확인한다. + +## v0b 초안: 바이트와 영속 문서 + +```text +layout Edit { + start: u32le + remove: u32le + insert: bytes +} + +state documents: bytes by key # 키마다 하나의 바이트 값. 런타임이 버전을 붙여 영속화한다 +input edit = message Edit by key # 키와 기준 버전을 가진 메시지 +input show = message by key + +on edit { + documents[key].splice(edit.start, edit.remove, edit.insert) + reply edit.insert +} + +on show { + reply documents[key] +} +``` + +- 이벤트 트랜잭션이 곧 Pure draft다. 핸들러가 성공하면 draft를 커밋하고, 기준 버전이 다르면 충돌이다. +- 바이트 값은 익스텐트 열이다. 연속 버퍼를 언어에서 드러내지 않는다. +- `get/put` 핸들러, `store.read/splice` 호출, `request.revision`은 언어에서 사라진다. HTTP·CLI 호스트가 입력과 응답으로 바꾼다. |
