diff options
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/design/001-language-v0.md | 5 | ||||
| -rw-r--r-- | docs/design/002-dsl-direction.md | 44 |
2 files changed, 45 insertions, 4 deletions
diff --git a/docs/design/001-language-v0.md b/docs/design/001-language-v0.md index 5be574d..1f934fb 100644 --- a/docs/design/001-language-v0.md +++ b/docs/design/001-language-v0.md @@ -1,6 +1,7 @@ # aup v0 — 한 언어, 한 모듈 형식 -2026-09-25. 상태: v0a(scalar)와 v0b(바이트·영속 문서·text·커서) 구현. text 문법은 [002](002-dsl-direction.md). +2026-09-25. 상태: v0a(scalar)와 v0b(바이트·영속 문서·text·커서), v0c의 레코드·리스트·인덱스 구현. +text와 리스트 문법은 [002](002-dsl-direction.md). 착수 기준: @@ -47,7 +48,7 @@ on frame { # 1/60초 진행. 핸들러 안에서 dt를 쓸 ``` - 선언과 문장은 줄바꿈이나 `;`로 끝난다. 이름은 ASCII `[A-Za-z_][A-Za-z_0-9]*`, 31바이트 이하다. -- 예약어: `state input view on if else key frame dt min max clamp`. +- 예약어: `state input view on if else key frame dt min max clamp message by bytes u32 reply require record`. - 키: `Space Enter ArrowLeft ArrowRight ArrowUp ArrowDown KeyA..KeyZ Digit0..Digit9`. 입력 이름과 키는 각각 한 번만 쓴다. 상태·입력·보기의 이름공간은 서로 겹칠 수 없다. - 식: 숫자, 상태 이름, `dt`(핸들러 안에서만), 괄호, 단항 `- !`, 이항 `* /`, `+ -`, diff --git a/docs/design/002-dsl-direction.md b/docs/design/002-dsl-direction.md index 2b419c9..c0d237c 100644 --- a/docs/design/002-dsl-direction.md +++ b/docs/design/002-dsl-direction.md @@ -1,6 +1,6 @@ # 002 — DSL 방향과 text -2026-09-25. 상태: 방향 확정, v0b·v0c에서 구현. +2026-09-25. 상태: 방향 확정. v0b 구현, v0c는 레코드·리스트·인덱스까지 구현. ## 위치 @@ -64,7 +64,7 @@ view current = note.line(at) # 커서가 있는 줄. 복사하지 않� |---|---|---| | v0a ✅ | 스칼라 상태, 키 입력, 핸들러, 보기 | 워크벤치 엔진과 비트 단위 일치 | | v0b ✅ | `bytes`, 키별 영속 문서, `message` 입력, 응답, `require`, `text`(리터럴·보간·`cursor in`·`char`/`line`), `text` 입력 | 기존 편집기 CLI와 바이트 단위 일치, text 편집이 참조 모델과 일치 | -| v0c | `i64 bool`, `record`, `list`/`map`, `index of`, 순수 `fn`, `use` 모듈 | 모든 연산에 실행량 상한 | +| v0c | `record`, `list of`, `index of` ✅ / 항목 투영, 조건식, 순수 `fn`, `use` 모듈, `i64 bool`, `map` | 모든 연산에 실행량 상한, 리스트가 참조 모델과 일치 ✅ | | v0d | `use vega`로 첫 인터페이스 투영(목록·표·커서·톤) | 한 명세가 두 표면 이상에서 동작 | ### 구현된 text (v0b) @@ -83,4 +83,44 @@ view current = note.line(at) # 커서가 있는 줄. 복사하지 않� 보기가 Python 참조 모델과 같다. 이스케이프와 숫자 표시(`1e+21`, `0.30000000000000004`, `2.5e-7`, `-0`은 `0`)를 확인한다. 컴파일러와 Pure 실행기를 각각 sanitizer로 빌드해 같은 검사를 통과했다. +### 구현된 레코드·리스트 (v0c-1) + +`examples/tasks.aup`가 할 일 목록 전체다. + +```text +record Task { + title: text # text 필드. 기본값은 "" (title: text = "..." 로 바꾼다) + done = 0 # 수 필드와 기본값 +} + +state tasks: list of Task # 런타임이 소유하는 항목 목록 +state at: index of tasks # 항상 tasks의 항목을 가리키는 위치 + +on typed { tasks.append(Task { title: typed }) } # 빠진 필드는 기본값 +on toggle.down { tasks[at].done = !tasks[at].done } +on drop.down { tasks.remove(at) } +on again.down { tasks.insert(at, Task { title: tasks[at].title }) } +on down.down { at = at + 1 } # 마지막 항목에서 멈춘다 + +view current = tasks[at].title +view status = "{at.position + 1}/{tasks.count}" +``` + +- **위치는 정수가 아니다.** 커서처럼 `index of 리스트` 타입을 둔다. 인덱스는 항상 그 리스트의 항목을 + 가리키고(빈 리스트면 0), 앞에 넣거나 지워도 같은 항목을 따라가며, 가리키던 항목이 지워지면 다음 항목 + (없으면 마지막)으로 간다. `at + n`, `at - n`은 처음과 마지막에서 멈춘다. `.first`/`.last`, `.position`(앞 항목 수). +- **다른 리스트의 인덱스는 컴파일 오류다.** `ys[at]`처럼 `xs`의 인덱스로 `ys`를 읽는 모듈은 Pure도 로드 단계에서 거부한다. +- **항목 읽기는 실패할 수 있다.** 빈 리스트의 `tasks[at]`은 이벤트를 `not_found`로 실패시킨다(아무것도 바뀌지 않음). + 보기는 그때 값이 없다(`pure-run`은 `null`). +- **변경은 되돌릴 수 있다.** 리스트 변경은 이벤트마다 기록되고, 이벤트가 실패하면 모두 되돌린다. +- **레코드를 바꿔도 데이터가 남는다.** 모듈을 교체할 때 리스트는 이름으로 남고, 레코드가 바뀌었으면 항목마다 + 이름과 타입이 같은 필드를 옮기고 새 필드는 기본값을 쓴다. 마이그레이션 스크립트가 필요 없다. +- 레코드 값(`Task { ... }`)은 아직 `append`/`insert`의 인자로만 쓴다. 레코드 상태, 항목 전체 읽기, 정렬·검색은 없다. + +한도: 레코드 8개, 레코드당 필드 16개, 전체 필드 64개, 리스트당 항목 65,536개. + +검증: 무작위 추가·이동·토글·복사·이름 바꾸기·지우기 4,800단계(빈 리스트에서 실패하는 이벤트 약 500건 포함)에서 +리스트, 인덱스, 보기, 실패 여부가 Python 참조 모델과 같다. 필드를 더하고 순서를 바꾼 레코드로 교체해도 항목이 +남는다. 진단 25건을 더했다. + 구현은 C로 손수 쓴 재귀 하강 파서를 유지한다. 문법은 EBNF로 문서화하고, 이후 `aup fmt`와 언어 서버를 붙인다. |
