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:
+86
-7
@@ -144,10 +144,8 @@ let root_capability name : value option =
|
||||
match args with
|
||||
| [ VStr path ] -> (
|
||||
try VEnum ("Result", "Ok", [ VStr (read_whole path) ])
|
||||
with Sys_error m ->
|
||||
VEnum ("Result", "Err", [ VStr m ]))
|
||||
| _ -> VEnum ("Result", "Err", [ VStr "read: 경로가 필요합니다" ])
|
||||
);
|
||||
with Sys_error m -> VEnum ("Result", "Err", [ VStr m ]))
|
||||
| _ -> VEnum ("Result", "Err", [ VStr "read: 경로가 필요합니다" ]) );
|
||||
] ))
|
||||
| "Args" ->
|
||||
Some
|
||||
@@ -160,15 +158,56 @@ let root_capability name : value option =
|
||||
Some (VScope "root")
|
||||
| _ -> None
|
||||
|
||||
(* 런타임이 구현한 이름 전부. std/*.cool의 선언과 이 목록이 어긋나면 검사는
|
||||
통과하고 실행이 죽는다 — 그 간극을 테스트가 막는다 (docs/friction.md F7).
|
||||
v1에서 std를 coollang으로 구현하면 이 목록 자체가 사라진다. *)
|
||||
let implemented =
|
||||
[
|
||||
"string.len";
|
||||
"string.is_empty";
|
||||
"string.concat";
|
||||
"string.split";
|
||||
"string.join";
|
||||
"string.trim";
|
||||
"string.starts_with";
|
||||
"string.contains";
|
||||
"int.show";
|
||||
"int.abs";
|
||||
"int.parse";
|
||||
"bool.show";
|
||||
"list.len";
|
||||
"list.is_empty";
|
||||
"list.first";
|
||||
"list.nth";
|
||||
"list.push";
|
||||
"list.concat";
|
||||
"list.reverse";
|
||||
"list.each";
|
||||
"list.map";
|
||||
"list.filter";
|
||||
"list.fold";
|
||||
"option.is_some";
|
||||
"option.map";
|
||||
"option.unwrap_or";
|
||||
"option.ok_or";
|
||||
"result.is_ok";
|
||||
"result.map";
|
||||
"result.map_err";
|
||||
"result.unwrap_or";
|
||||
]
|
||||
|
||||
let builtin pos name (args : value list) : value =
|
||||
match (name, args) with
|
||||
| "string.concat", [ VStr a; VStr b ] -> VStr (a ^ b)
|
||||
| "string.len", [ VStr a ] -> VInt (String.length a)
|
||||
| "string.is_empty", [ VStr a ] -> VBool (a = "")
|
||||
| "string.split", [ VStr s; VStr sep ] -> VList (List.map (fun x -> VStr x) (split_on s sep))
|
||||
| "string.split", [ VStr s; VStr sep ] ->
|
||||
VList (List.map (fun x -> VStr x) (split_on s sep))
|
||||
| "string.trim", [ VStr s ] -> VStr (String.trim s)
|
||||
| "string.starts_with", [ VStr s; VStr p ] ->
|
||||
VBool (String.length s >= String.length p && String.sub s 0 (String.length p) = p)
|
||||
VBool
|
||||
(String.length s >= String.length p
|
||||
&& String.sub s 0 (String.length p) = p)
|
||||
| "string.contains", [ VStr s; VStr n ] -> VBool (find_sub s n <> None)
|
||||
| "int.show", [ VInt n ] -> VStr (string_of_int n)
|
||||
| "int.abs", [ VInt n ] -> VInt (abs n)
|
||||
@@ -182,6 +221,27 @@ let builtin pos name (args : value list) : value =
|
||||
| "list.push", [ VList xs; x ] -> VList (xs @ [ x ])
|
||||
| "list.concat", [ VList xs; VList ys ] -> VList (xs @ ys)
|
||||
| "list.reverse", [ VList xs ] -> VList (List.rev xs)
|
||||
| "list.first", [ VList xs ] -> (
|
||||
match xs with
|
||||
| [] -> VEnum ("Option", "None", [])
|
||||
| x :: _ -> VEnum ("Option", "Some", [ x ]))
|
||||
| "list.nth", [ VList xs; VInt i ] -> (
|
||||
match List.nth_opt xs i with
|
||||
| Some x -> VEnum ("Option", "Some", [ x ])
|
||||
| None -> VEnum ("Option", "None", []))
|
||||
| "string.join", [ VStr sep; VList parts ] ->
|
||||
VStr
|
||||
(String.concat sep
|
||||
(List.map (function VStr s -> s | v -> show v) parts))
|
||||
| "option.is_some", [ VEnum ("Option", v, _) ] -> VBool (v = "Some")
|
||||
| "option.unwrap_or", [ VEnum ("Option", "Some", [ x ]); _ ] -> x
|
||||
| "option.unwrap_or", [ _; fallback ] -> fallback
|
||||
| "option.ok_or", [ VEnum ("Option", "Some", [ x ]); _ ] ->
|
||||
VEnum ("Result", "Ok", [ x ])
|
||||
| "option.ok_or", [ _; e ] -> VEnum ("Result", "Err", [ e ])
|
||||
| "result.is_ok", [ VEnum ("Result", v, _) ] -> VBool (v = "Ok")
|
||||
| "result.unwrap_or", [ VEnum ("Result", "Ok", [ x ]); _ ] -> x
|
||||
| "result.unwrap_or", [ _; fallback ] -> fallback
|
||||
| _ ->
|
||||
fail pos (Printf.sprintf "%s은(는) 런타임이 제공하지 않습니다 (표준 라이브러리가 아직 없습니다)" name)
|
||||
|
||||
@@ -305,9 +365,28 @@ and apply st pos f args =
|
||||
| [ VList xs; f ] ->
|
||||
VList
|
||||
(List.filter
|
||||
(fun x -> match apply st pos f [ x ] with VBool b -> b | _ -> false)
|
||||
(fun x ->
|
||||
match apply st pos f [ x ] with VBool b -> b | _ -> false)
|
||||
xs)
|
||||
| _ -> fail pos "list.filter는 리스트와 함수를 받습니다")
|
||||
| VBuiltin "option.map" -> (
|
||||
match args with
|
||||
| [ VEnum ("Option", "Some", [ x ]); f ] ->
|
||||
VEnum ("Option", "Some", [ apply st pos f [ x ] ])
|
||||
| [ o; _ ] -> o
|
||||
| _ -> fail pos "option.map은 Option과 함수를 받습니다")
|
||||
| VBuiltin "result.map" -> (
|
||||
match args with
|
||||
| [ VEnum ("Result", "Ok", [ x ]); f ] ->
|
||||
VEnum ("Result", "Ok", [ apply st pos f [ x ] ])
|
||||
| [ r; _ ] -> r
|
||||
| _ -> fail pos "result.map은 Result와 함수를 받습니다")
|
||||
| VBuiltin "result.map_err" -> (
|
||||
match args with
|
||||
| [ VEnum ("Result", "Err", [ e ]); f ] ->
|
||||
VEnum ("Result", "Err", [ apply st pos f [ e ] ])
|
||||
| [ r; _ ] -> r
|
||||
| _ -> fail pos "result.map_err는 Result와 함수를 받습니다")
|
||||
| VBuiltin "list.fold" -> (
|
||||
match args with
|
||||
| [ VList xs; init; f ] ->
|
||||
|
||||
Reference in New Issue
Block a user