std: 마찰 보고의 F1/F3/F6/F7 처리 — 292줄이 244줄로

문법은 건드리지 않았다. 표본이 한 사람이 쓴 300줄 하나뿐인데 되돌리기
비싼 축을 움직일 수는 없다. std 보강만 했다.

추가: List.first/nth, String.join, std/option.cool, std/result.cool.

samples/app 재작성 결과 config.cool 196 → 148줄. head_or, second_or,
Pick, take_at, first_text, first_entry가 통째로 사라졌다. 예측 40줄,
실제 48줄 — F1의 값이 확인됐다.

F3은 줄 수로 값이 안 보인다. main.cool은 96줄 그대로다. 4단 중첩
String.concat이 4줄짜리 String.join 배열이 됐으니 줄 수가 같다. 읽기는
확실히 나아졌다. 줄 수는 읽기 좋음의 대리 지표일 뿐이고 여기서 그 대리가
깨진다 — 다음 개밥 먹기는 다른 것을 재야 한다.

F7: Interp.implemented와 std/*.cool 선언이 서로를 덮는지 테스트가 양방향
으로 검사한다. 어긋나면 빌드가 깨진다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019ZVDeU6KLuUVL3gs18Hm3E
This commit is contained in:
2026-08-30 16:20:23 +09:00
co-authored by Claude Opus 5
parent 7be05be77f
commit a9f6527825
11 changed files with 260 additions and 90 deletions
+41 -6
View File
@@ -1242,22 +1242,22 @@ let () =
let () =
let st = Session.create ~root:"../samples/app" ~std:"../std" () in
match Session.run ~args:[ "../samples/app/example.conf" ] st
"../samples/app/main.cool"
match
Session.run
~args:[ "../samples/app/example.conf" ]
st "../samples/app/main.cool"
with
| Error e ->
Printf.printf " (실행 오류: %s)\n" (Session.string_of_error e);
check "app: 설정 리포트가 돈다" false
| Ok out ->
check "app: 항목과 문제를 센다"
(has_sub out "항목 5개, 문제 2개");
check "app: 항목과 문제를 센다" (has_sub out "항목 5개, 문제 2개");
check "app: 값의 타입을 모양으로 정한다"
(has_sub out "threads = 4 (number)"
&& has_sub out "verbose = true (flag)"
&& has_sub out "name = \"coollang\" (text)");
check "app: 문제에 줄 번호가 붙는다"
(has_sub out "10행: 이름이 비어 있습니다"
&& has_sub out "11행: = 가 하나여야 합니다");
(has_sub out "10행: 이름이 비어 있습니다" && has_sub out "11행: = 가 하나여야 합니다");
check "app: 타입 있는 조회" (has_sub out "port = 8080")
let () =
@@ -1271,3 +1271,38 @@ let () =
match Session.run ~args:[ "/없는/파일.conf" ] st "../samples/app/main.cool" with
| Ok out -> check "app: 없는 파일을 Err로 돌려준다" (has_sub out "오류: ")
| Error _ -> check "app: 없는 파일을 Err로 돌려준다" false
(* std 선언과 런타임 구현이 어긋나면 검사는 통과하고 실행이 죽는다.
v0에서 둘은 다른 파일에 있으므로 일치는 테스트가 지킨다 (friction F7). *)
let () =
let dir = "../std" in
let declared =
Sys.readdir dir |> Array.to_list
|> List.filter (fun f -> Filename.check_suffix f ".cool")
|> List.concat_map (fun f ->
let m = ref "" in
(match Driver.ast (Filename.concat dir f) with
| Error _ -> ()
| Ok _ -> m := Filename.remove_extension f);
match Driver.ast (Filename.concat dir f) with
| Error _ -> []
| Ok ast ->
List.filter_map
(function
| Ast.I_fn { decl; _ } -> Some (!m ^ "." ^ decl.fn_name)
| _ -> None)
ast.Ast.items)
in
check "std에 선언이 있다" (List.length declared > 20);
List.iter
(fun name ->
check
(Printf.sprintf "std 선언 %s에 런타임 구현이 있다" name)
(List.mem name Interp.implemented))
declared;
List.iter
(fun name ->
check
(Printf.sprintf "런타임 구현 %s에 std 선언이 있다" name)
(List.mem name declared))
Interp.implemented