Compiler messages are now printed in color with their respective code, field access support has been added in the type checker. However, field access nodes that contain other field access nodes are not yet supported. Signed-off-by: Slendi <slendi@socopon.com>
124 lines
2.5 KiB
Odin
124 lines
2.5 KiB
Odin
package main
|
|
|
|
import "core:fmt"
|
|
import "core:os"
|
|
|
|
main :: proc() {
|
|
handle: os.Handle
|
|
file_name := "<stdin>"
|
|
if len(os.args) >= 2 {
|
|
errno: os.Errno
|
|
handle, errno = os.open(os.args[1])
|
|
if errno != 0 {
|
|
fmt.printf("Error opening file\n", errno)
|
|
return
|
|
}
|
|
file_name = os.args[1]
|
|
} 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)
|
|
|
|
ast := parser_parse(&parser)
|
|
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
|
|
}
|
|
//fmt.printf("%s\n", msg)
|
|
}
|
|
if contains_errors {
|
|
return
|
|
}
|
|
}
|
|
fmt.println("After parse:")
|
|
//node_print(ast)
|
|
clear(&g_message_list)
|
|
type_check(ast, nil)
|
|
fmt.println("After type check:")
|
|
//node_print(ast)
|
|
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
|
|
}
|
|
//fmt.printf("%s\n", msg)
|
|
}
|
|
if contains_errors {
|
|
return
|
|
}
|
|
}
|
|
|
|
//node_print(ast)
|
|
|
|
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)
|
|
|
|
generate_llvm(ctx, module, builder, ast)
|
|
|
|
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
|
|
}
|