package main import "core:fmt" import "core:os" import "core:time" main :: proc() { fmt.println("Speedcat bootstrap compiler") fmt.println("===========================") handle: os.Handle options := parse_args(&os.args) file_name := options.file if file_name != "" { errno: os.Errno handle, errno = os.open(file_name) if errno != 0 { fmt.printf("Error opening file\n", errno) return } } else { handle = os.stdin } defer os.close(handle) data, err := os.read_entire_file_from_handle(handle) if !err { fmt.printf("Error reading file\n", err) return } u8_arr: [dynamic]u8 for ch in data { append(&u8_arr, u8(ch)) } lexer := lexer_create(&u8_arr, file_name) parser := parser_create(lexer) parser_time_start := time.now() ast := parser_parse(&parser) parser_duration := time.since(parser_time_start) if len(g_message_list) > 0 { contains_errors := false for &msg in g_message_list { message_print(&msg, &data) if msg.level == .Error || msg.level == .Fatal { contains_errors = true } } if contains_errors { os.exit(1) } } clear(&g_message_list) type_check_start := time.now() type_check(ast, nil) type_check_duration := time.since(type_check_start) if len(g_message_list) > 0 { contains_errors := false for &msg in g_message_list { message_print(&msg, &data) if msg.level == .Error || msg.level == .Fatal { contains_errors = true } } if contains_errors { os.exit(1) } } if options.dump_ast { node_print(ast) } fmt.println("Time report") fmt.println("===========") most_printed := 0 printed := fmt.printf( "Parsing took: % 10dns (%.3fms)\n", time.duration_nanoseconds(parser_duration), time.duration_milliseconds(parser_duration), ) most_printed = max(printed, most_printed) printed = fmt.printf( "Type checker took: % 10dns (%.3fms)\n", time.duration_nanoseconds(type_check_duration), time.duration_milliseconds(type_check_duration), ) most_printed = max(printed, most_printed) llvm_duration: time.Duration = 0 defer { for most_printed > 1 { fmt.printf("-") most_printed -= 1 } fmt.printf( "\nTotal time: % 10dns (%.3fms)\n\n", time.duration_nanoseconds(llvm_duration + type_check_duration + parser_duration), time.duration_milliseconds(llvm_duration + type_check_duration + parser_duration), ) } if options.dont_emit_llvm { return } name: string if handle == os.stdin { name = "stdin" } else { name = os.args[1] } name_dyn := [dynamic]u8{} for ch in transmute([]u8)name { append(&name_dyn, u8(ch)) } module_name := parse_use_path2(name_dyn) module_name = main_module_name_from_filename(module_name) if len(module_name) == 0 { clear(&module_name) append(&module_name, 'm') append(&module_name, 'a') append(&module_name, 'i') append(&module_name, 'n') } ctx := LLVMContextCreate() defer LLVMContextDispose(ctx) module := LLVMModuleCreateWithNameInContext(cstring(raw_data(module_name[:])), ctx) defer LLVMDisposeModule(module) builder := LLVMCreateBuilderInContext(ctx) llvm_start := time.now() generate_llvm(ctx, module, builder, ast) llvm_duration = time.since(llvm_start) printed = fmt.printf( "LLVM generation took: % 10dns (%.3fms)\n", time.duration_nanoseconds(llvm_duration), time.duration_milliseconds(llvm_duration), ) append(&module_name, '.') append(&module_name, 'l') append(&module_name, 'l') LLVMPrintModuleToFile(module, cstring(raw_data(module_name[:])), nil) } main_module_name_from_filename :: proc(fname: [dynamic]u8) -> (module_name: [dynamic]u8) { temp_name := [dynamic]u8{} for ch in fname { if ch == '/' || ch == '\\' { clear(&temp_name) } else { append(&temp_name, ch) } } for ch in temp_name { if ch == '.' { break } append(&module_name, ch) } return }