이 문서는 의도한 설계를 현재형으로 기술한다. 전부 구현된 것은 아니다. 오늘 실제로 동작하는 범위는
docs/LANGUAGE.md(언어 표면)와docs/STATUS.md(실측 상태)가 정본이며, 아직 만들지 않은 항목에는 ⏳ 미구현을 붙였다. 설계 기록으로서의 값을 유지하려고 문장을 미래형으로 바꾸지는 않았다.
개발자가 보는 계층과 실행 계층을 분리한다.
변환은 컴파일 타임에만 일어난다. 실행 시점에는 네이티브 코드만 남긴다.
[표면 문법 소스 .mls]
│ parse / typecheck
▼
[내부 IR]
│ lower to native backend
▼
[네이티브 오브젝트]
│ link + optional protect
▼
[배포 모듈 .dll (⏳ .so/ELF·.mll 컨테이너는 미구현)]
│ C ABI
▼
[호스트 앱: C ✅ CI 게이트 / Delphi ✅ 로컬 게이트 / C++ ✅ 헤더 컴파일만 / C# ⏳ 미검증]
파일 확장자는 가칭이다. 확정 전.
- Lex / Parse
표면 문법 → AST - Resolve / Typecheck
강한 정적 타입. 호스트가 제공한 인터페이스 정의도 여기서 검증(⏳ 미구현 — 호스트 인터페이스 입력이 아직 없다) - IR
언어 중립에 가깝되, 네이티브/Delphi 실행 모델(값 타입, 명시적 수명 후보)을 표현할 수 있어야 함 - Codegen
내부 IR →no_std·extern "C"·repr(C)Rust →cargo cdylib(D19, 잠정). C-emit 백엔드 슬롯은 열려 있고 LLVM 직접 방출은 이연했다 — 이 줄은 "LLVM 또는 기존 네이티브 툴체인에 lowering"이라는 후보로 적혀 있었으나, D19가 2026-08-28에 정했고 그 뒤로 계속 출하돼 왔다(compiler/src/codegen.rs).
“내부가 Delphi 방식”이 Delphi 컴파일러를 반드시 호출한다는 뜻은 아님.
의미 모델이 Object Pascal/네이티브에 가깝다는 뜻이다. - Packaging
export 테이블, 버전 심볼, 그리고 인터페이스 지문(ml_iface_hash_<모듈>, #105) —iface.rs가ml-iface/1매니페스트를 만들고 생성 헤더가ML_<모듈>_IFACE_HASH를 박으며, 참조 C 호스트 둘이 어긋난 모듈을 거부한다(실측). ⏳ 미구현으로 남은 것은.mll컨테이너다(D18: 커스텀 컨테이너는 P1).(2026-09-22 정정: 이 줄은 지문이 출하된 뒤에도 없는 것으로 적고 있었다 — 같은 파일 아래 문단이 지문의 존재를 전제하고 그 한계를 설명하는데도. 옛 표현을 인용하지 않는다:
no_document_calls_interface_metadata_unimplemented가 그것을 금지하므로, 인용하면 정정문이 자기 가드를 트립시킨다 — 이 저장소에서 오늘만 네 번째다.) - Protect
strip과 심볼 제거는 구현됨(모든 빌드에 적용, 실측). 이후의 단계적 강화(P1·P2)와 "배포 빌드만" 이라는 구분(D13)은 ⏳ 미구현 — 지금은 빌드 프로파일이 하나다
- 로더 — 오늘은 호스트 쪽이다(
LoadLibrary/GetProcAddress). 얇은 C 런타임은 ⏳ 미구현 - C ABI 호출 규약
- 선택적 무결성 검사 — ⏳ 미구현(P1,
SECURITY.md) - 에러 코드 규약(D17, 구현됨). 모듈용 할당자 등 그 밖의 런타임 지원은 ⏳ 미구현
런타임에 존재하지 말아야 할 것:
- 소스 파서
- 표면 문법 인터프리터
- 일반 eval
모듈은 플러그인이다.
- 호스트가 모듈을
load - 모듈 export를 호스트가 호출한다. 반대 방향(호스트가 허용한 함수/객체를 모듈에 넘기는 것)은 ⏳ 미구현
- 모듈 교체 = 파일 교체 + 재로드. 모듈의 시그니처가 그대로인 한 호스트 재빌드 없음.
이 조건은 실측으로 좁혀졌다(2026-09-01): 규칙을 i32 코드로 표현하면 그 코드의 어휘가
호스트에 살게 되어, 모듈에 케이스 하나를 더하면 재빌드하지 않은 호스트가 모르는 코드를 출력한다.
임계값 변경은 파일 교체로 나가고, 케이스 집합 확장은 호스트 재빌드를 요구한다
(
docs/slices/SPEC-string-return.md§0.1). 배열도 같다 — 원소 개수를 파라미터 개수로 흉내내면 개수가 바뀔 때 옛 호스트가 조용히 틀린 값을 받거나 segfault한다(실측). 세 번째 좁힘(2026-09-07, STATUS §9-9): 규칙의 일정이 바뀌어도 재빌드가 필요하다. fold로 쪼갠 호스트는 "패스가 몇 번이고 그 사이에 무엇이 옮겨지는가"를 자기 코드에 갖는다. 순위를 한 번 매기는 전제로 얼린 호스트에 제수법 모듈을 끼우면 크래시 없이 다른 규칙의 답을 내고, 시그니처가 같으므로 인터페이스 지문도 이것을 보지 못한다(실측).
⏳ 이 표는 D13이 의도한 구분이며, 아직 구현되지 않았다. 현재는 빌드 프로파일이 하나뿐이라 개발 빌드도 배포 빌드와 같게 strip된다.
| 개발 | 배포 | |
|---|---|---|
| 소스 | 로컬에만 | 없음 |
| 심볼/디버그 | 가능 | 제거 |
| 보호 | 약하거나 없음 | 단계적 강화 |
| 피드백 | 빠른 컴파일, 명확한 타입 에러 | 실행과 무결성 |
브라우저에서 DLL을 실행하지 않는다.
웹이 필요해지면 별도 WASM 타깃을 추가하는 것이지, 기본 모델을 WASM으로 바꾸지 않는다.
compiler/: 프론트엔드 + IRbackend/: 네이티브 codegenruntime/: 얇은 C ABI 런타임host/delphi,host/c: 바인딩packager/: 모듈 포맷
MVP는 compiler 최소 + C ABI + Delphi 또는 C 호스트 하나면 충분하다.
위는 권장 경계이고, 아래는 그것이 실제 디렉터리로 어떻게 내려앉았는지의 대응표다. 나머지는 조기 경계이므로 필요해질 때 만든다(빈 크레이트를 미리 만들지 않는다).
여기에 "이것뿐이다"라고 쓰지 않는다. 그렇게 적혀 있었고, 그 문장이 두 번 거짓이 됐다 —
hosts/delphi-host/(#111)와hosts/c-host-link/(#126)가 생겼는데 표는 그대로였다. 디렉터리의 정본은 트리이고, 이 표는 권장 경계 ↔ 실재의 대응을 설명하는 자리다.
| 경로 | 내용 | 상태 |
|---|---|---|
compiler/ |
lex → parse → typecheck → IR → codegen + mlc build CLI |
있음 (codegen도 여기) |
runtime/ |
C ABI 헤더·예약 심볼 규약 | 있음 (헤더만, 런타임 코드 없음) |
hosts/rust-oracle/ |
kernel32 로더 + PE export 리더 (테스트 오라클) | 있음 |
examples/ |
.mls 예제 |
있음 |
backend/ · packager/ |
— | 미생성(실측: 두 디렉터리 모두 없다) |
host/delphi |
hosts/delphi-host/ |
실재하고, 로컬 게이트가 있다. MATHLESS_GATE_DELPHI가 dcc64로 빌드해 호출한다 — 에디션이 명령줄 빌드를 거부하므로 게이트가 IDE(bds.exe -b)를 부른다(STATUS §9-20). CI 게이트는 아니다: 러너에 Delphi도 대화형 세션도 없다. Free Pascal은 CI에서 매번 돈다(MATHLESS_GATE_FPC·MATHLESS_GATE_FPC_HOST) |
hosts/c-host-link/ |
— | 있음 — 헤더를 include하고 .lib을 링크하는 두 번째 소비 경로. GetProcAddress가 한 번도 나오지 않는다(#126) |
host/c |
hosts/c-host/ |
이름만 다르다 — 실재한다. MSVC로 빌드하는 C11 호스트가 수용 D를 닫고 CI의 정본 잡이 이를 실행한다(.github/workflows/ci.yml). 이 표는 권장 경계를 기준으로 쓰였고, 실제 디렉터리는 hosts/ 아래에 있다 |