speedcat/src/main.odin
Slendi 5af9845f93 Add command line arguments and make time printing nicer
This patch adds the following arguments:

1. `--dump-ast` or `-d`: This dumps the Abstract Syntax Tree
2. `--dont-emit-llvm` or `-L`: This skips the LLVM generation step only
   parsing and type checking. Useful for debugging.

Besides this, formatting of the time each compiler step took is also
improved and easier to read now.

Signed-off-by: Slendi <slendi@socopon.com>
2024-05-04 13:27:25 +02:00

170 lines
3.8 KiB
Odin

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 != "<stdin>" {
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
}