let usage = {|coollang toolchain 사용법: coolc check ... 타입/effect/capability 검사 (import를 따라 모듈 그래프 전체) coolc test [필터] 모듈 그래프의 test 블록 실행 coolc iface interface 표면과 해시 출력 coolc run [인자...] typed IR 인터프리터로 실행 coolc tokens 토큰 덤프 (렉서 디버깅) coolc ast 구문 트리 덤프 (파서 디버깅) coolc deps 외부 참조 목록 (모듈의 의존 표면) coolc version 버전 출력 |} let report_errors errors = List.iter (fun e -> prerr_endline (Coollang.Driver.string_of_error e)) errors; 1 let report = function Ok () -> 0 | Error errors -> report_errors errors let dump_tokens file = match Coollang.Driver.tokens file with | Error errors -> report_errors errors | Ok tokens -> List.iter (fun t -> print_endline (Coollang.Token.show t)) tokens; 0 let dump_ast file = match Coollang.Driver.ast file with | Error errors -> report_errors errors | Ok m -> List.iter (fun it -> print_endline (Coollang.Ast.show_item it)) m.Coollang.Ast.items; 0 (* import를 따라 모듈 그래프를 로드하고 전부 검사한다. root는 첫 파일의 디렉터리다. *) let check_graph files = match files with | [] -> prerr_endline "검사할 파일이 없습니다"; 2 | first :: _ -> let st = Coollang.Session.create ~root:(Filename.dirname first) () in List.iter (fun f -> Coollang.Session.load st f) files; let errors = Coollang.Session.errors st in List.iter (fun e -> prerr_endline (Coollang.Session.string_of_error e)) errors; if errors = [] then 0 else 1 let dump_iface file = let st = Coollang.Session.create ~root:(Filename.dirname file) () in Coollang.Session.load st file; match Coollang.Session.find st file with | None -> 1 | Some e -> Printf.printf "hash %s\n" e.iface.Coollang.Iface.hash; List.iter (fun it -> print_endline (Coollang.Ast.show_item it)) e.iface.Coollang.Iface.items; 0 let dump_deps file = match Coollang.Driver.resolve file with | Error errors -> report_errors errors | Ok info -> List.iter (fun (name, (p : Coollang.Token.pos)) -> Printf.printf "%d:%d %s\n" p.line p.col name) info.Coollang.Resolve.externals; 0 let () = let argv = Array.to_list Sys.argv in let code = match List.tl argv with | "check" :: files -> check_graph files | [ "iface"; file ] -> dump_iface file | "test" :: file :: rest -> ( let filter = match rest with f :: _ -> f | [] -> "" in let st = Coollang.Session.create ~root:(Filename.dirname file) () in match Coollang.Session.test ~filter st file with | Error errors -> List.iter (fun e -> prerr_endline (Coollang.Session.string_of_error e)) errors; 1 | Ok results -> let failed = List.filter (fun (r : Coollang.Interp.test_result) -> r.t_failure <> None) results in List.iter (fun (r : Coollang.Interp.test_result) -> match r.t_failure with | None -> () | Some (p, msg) -> Printf.printf "FAIL %s:%d %s\n %s\n" r.t_module r.t_pos.line r.t_name msg; ignore p) results; Printf.printf "%s 테스트 %d개 중 %d개 통과\n" (if failed = [] then "ok " else "실패") (List.length results) (List.length results - List.length failed); if failed = [] then 0 else 1) | "run" :: file :: args -> ( let st = Coollang.Session.create ~root:(Filename.dirname file) () in match Coollang.Session.run ~args st file with | out, None -> print_string out; 0 | out, Some e -> (* 실패해도 그때까지의 출력을 먼저 보여준다 *) print_string out; flush stdout; prerr_endline (Coollang.Session.string_of_error e); 1) | [ "tokens"; file ] -> dump_tokens file | [ "ast"; file ] -> dump_ast file | [ "deps"; file ] -> dump_deps file | [ "version" ] -> print_endline Coollang.Version.string; 0 | [] | [ "help" ] | [ "--help" ] | [ "-h" ] -> print_string usage; 0 | cmd :: _ -> Printf.eprintf "알 수 없는 명령: %s\n\n%s" cmd usage; 2 in exit code