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:
+41
-6
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user