diff --git a/.gitignore b/.gitignore index 32fe286..90ba29a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ build/ +nest/ *.data diff --git a/bootstrap/main.c b/bootstrap/main.c index f17ad1b..24f52d2 100644 --- a/bootstrap/main.c +++ b/bootstrap/main.c @@ -15,6 +15,7 @@ #if LINK_LIBC #include #include +#include #endif typedef uint8_t u8; @@ -169,6 +170,64 @@ typedef struct StructName StructName declare_slice(u8); typedef Slice(u8) String; +// Array of strings +declare_slice(String); + +fn s32 string_first_ch(String string, u8 ch) +{ + s32 result = -1; + for (u64 i = 0; i < string.length; i += 1) + { + if (string.pointer[i] == ch) + { + result = i; + break; + } + } + + return result; +} + +fn s32 string_last_ch(String string, u8 ch) +{ + s32 result = -1; + u64 i = string.length; + while (i > 0) + { + i -= 1; + if (string.pointer[i] == ch) + { + result = i; + break; + } + } + + return result; +} + +fn String string_dir(String string) +{ + String result = {}; + auto index = string_last_ch(string, '/'); + if (index != -1) + { + result = s_get_slice(u8, string, 0, index); + } + + return result; +} + +fn String string_base(String string) +{ + String result = {}; + auto index = string_last_ch(string, '/'); + if (index != -1) + { + result = s_get_slice(u8, string, index + 1, string.length - 2); + } + + return result; +} fn u64 parse_decimal(String string) { @@ -1143,6 +1202,29 @@ fn void* arena_allocate_bytes(Arena* arena, u64 size, u64 alignment) return result; } +fn String arena_join_string(Arena* arena, Slice(String) pieces) +{ + u64 size = 0; + for (u64 i = 0; i < pieces.length; i += 1) + { + String piece = pieces.pointer[i]; + size += piece.length; + } + + u8* pointer = arena_allocate_bytes(arena, size + 1, 1); + auto* it = pointer; + for (u64 i = 0; i < pieces.length; i += 1) + { + String piece = pieces.pointer[i]; + memcpy(it, piece.pointer, piece.length); + it += piece.length; + } + assert(it - pointer == size); + *it = 0; + + return (String) { .pointer = pointer, .length = size }; +} + #define arena_allocate(arena, T, count) arena_allocate_bytes(arena, sizeof(T) * count, alignof(T)) #define arena_allocate_slice(arena, T, count) (Slice(T)){ .pointer = arena_allocate(arena, T, count), .length = count } @@ -1316,6 +1398,19 @@ fn StringMapPut string_map_put(StringMap* map, Arena* arena, String key, u32 val trap(); } +fn int file_write(String file_path, String file_data) +{ + int file_descriptor = syscall_open((char*)file_path.pointer, O_WRONLY | O_CREAT | O_TRUNC, 0644); + assert(file_descriptor != -1); + + auto bytes = syscall_write(file_descriptor, file_data.pointer, file_data.length); + assert(bytes == file_data.length); + + int close_result = syscall_close(file_descriptor); + assert(close_result == 0); + return 0; +} + fn String file_read(Arena* arena, String path) { String result = {}; @@ -4396,7 +4491,7 @@ fn void c_lower_node(VirtualBuffer(u8)* buffer, Thread* thread, NodeIndex node_i fn String c_lower(Thread* thread) { VirtualBuffer(u8) buffer = {}; - auto program_epilogue = strlit("#include " + auto program_epilogue = strlit("#include \n" "typedef uint8_t u8;\n" "typedef uint16_t u16;\n" "typedef uint32_t u32;\n" @@ -4512,207 +4607,6 @@ fn void thread_clear(Thread* thread) arena_reset(thread->arena); } -// Arena* arena = Arena::init_default(64*1024); -// -// auto main_c_path = strlit("main.c"); -// { -// auto main_c_content = strlit("int main()\n{\n return 0;\n}"); -// int fd = syscall_open("main.c", O_WRONLY | O_CREAT | O_TRUNC, 0644); -// assert(fd != -1); -// auto result = syscall_write(fd, main_c_content.pointer, main_c_content.length); -// assert(result >= 0); -// assert((u64)result == main_c_content.length); -// syscall_close(fd); -// } -// system("clang -c main.c -o main.o -Oz -fno-exceptions -fno-asynchronous-unwind-tables -fno-addrsig -fno-stack-protector -fno-ident"); -// system("objcopy --remove-section .note.GNU-stack main.o main2.o"); -// String main_o; -// { -// -// int fd = syscall_open("main2.o", 0, 0); -// assert(fd != -1); -// auto file_size = file_get_size(fd); -// -// auto file = arena->allocate_slice(file_size); -// auto read_bytes = syscall_read(fd, file.pointer, file.length); -// assert(read_bytes == file_size); -// main_o = file; -// syscall_close(fd); -// auto r1 = syscall_unlink("main.o"); -// assert(!r1); -// auto r2 = syscall_unlink("main2.o"); -// assert(!r2); -// auto r3 = syscall_unlink("main.c"); -// assert(!r3); -// } -// -// PinnedArray file = {}; -// auto elf_header = ELF::Header -// { -// .type = ELF::Type::relocatable, -// .machine = ELF::Machine::x86_64, -// .version = 1, -// .entry_point = 0, -// .program_header_offset = 0, -// .section_header_offset = 192, -// .flags = 0, -// .program_header_size = 0, -// .program_header_count = 0, -// .section_header_size = sizeof(ELF::SectionHeader), -// .section_header_count = 5, -// .section_header_string_table_index = 4, -// }; -// auto* original_elf_header = (ELF::Header*)&main_o[0]; -// file.append(struct_to_bytes(elf_header)); -// // .text -// -// // Code: -// // main: -// // xor eax, eax -// // ret -// file.append_one(0x31); -// file.append_one(0xc0); -// file.append_one(0xc3); -// for (int i = 0; i < 5; i += 1) -// { -// file.append_one(0); -// } -// -// // .symtab -// -// ELF::Symbol null_symbol = {}; -// file.append(struct_to_bytes(null_symbol)); -// -// ELF::Symbol symbol1 = { -// .name_offset = 1, -// .type = ELF::Symbol::Type::FILE, -// .binding = ELF::Symbol::Binding::LOCAL, -// .section_index = (u16)ELF::SectionIndex::ABSOLUTE, -// .value = 0, -// .size = 0, -// }; -// file.append(struct_to_bytes(symbol1)); -// -// ELF::Symbol symbol2 = { -// .name_offset = 8, -// .type = ELF::Symbol::Type::FUNCTION, -// .binding = ELF::Symbol::Binding::GLOBAL, -// .section_index = 1, -// .value = 0, -// .size = 3, -// }; -// file.append(struct_to_bytes(symbol2)); -// -// // .strtab -// // Null string -// file.append_one(0); -// -// file.append(strlit("main.c")); -// file.append_one(0); -// -// file.append(strlit("main")); -// file.append_one(0); -// -// // .shstrtab -// // Null string -// file.append_one(0); -// -// file.append(strlit(".symtab")); -// file.append_one(0); -// -// file.append(strlit(".strtab")); -// file.append_one(0); -// -// file.append(strlit(".shstrtab")); -// file.append_one(0); -// -// file.append(strlit(".text")); -// file.append_one(0); -// -// // Align -// file.append_one(0); -// file.append_one(0); -// -// assert(file.length == 0xc0); -// -// // Section headers -// ELF::SectionHeader null_section = {}; -// file.append(struct_to_bytes(null_section)); -// -// ELF::SectionHeader text_section = { -// .name_offset = 27, -// .type = ELF::SectionHeader::Type::program, -// .flags = { -// .alloc = 1, -// .executable = 1, -// }, -// .address = 0, -// .offset = 64, -// .size = 3, -// .link = 0, -// .info = 0, -// .alignment = 4, -// .entry_size = 0, -// }; -// file.append(struct_to_bytes(text_section)); -// -// ELF::SectionHeader symtab_section = { -// .name_offset = 1, -// .type = ELF::SectionHeader::Type::symbol_table, -// .flags = {}, -// .address = 0, -// .offset = 72, -// .size = 72, -// .link = 3, -// .info = 2, -// .alignment = alignof(ELF::Symbol), -// .entry_size = sizeof(ELF::Symbol), -// }; -// file.append(struct_to_bytes(symtab_section)); -// -// ELF::SectionHeader strtab_section = { -// .name_offset = 9, -// .type = ELF::SectionHeader::Type::string_table, -// .flags = {}, -// .address = 0, -// .offset = 144, -// .size = 13, -// .link = 0, -// .info = 0, -// .alignment = 1, -// .entry_size = 0, -// }; -// file.append(struct_to_bytes(strtab_section)); -// -// ELF::SectionHeader shstrtab_section = { -// .name_offset = 17, -// .type = ELF::SectionHeader::Type::string_table, -// .flags = {}, -// .address = 0, -// .offset = 157, -// .size = 33, -// .link = 0, -// .info = 0, -// .alignment = 1, -// .entry_size = 0, -// }; -// file.append(struct_to_bytes(shstrtab_section)); -// -// auto mine = file.slice(); -// auto original = main_o.slice(0, file.length); -// assert(mine.equal(original)); -// assert(file.length == main_o.length); -// -// { -// int fd = syscall_open("main.o", O_WRONLY | O_CREAT | O_TRUNC, 0644); -// assert(fd != -1); -// syscall_write(fd, file.pointer, file.length); -// -// syscall_close(fd); -// } -// -// system("clang main.o -o main.exe"); - #define DO_UNIT_TESTS 1 #if DO_UNIT_TESTS fn void unit_tests() @@ -4737,6 +4631,8 @@ extern "C" void entry_point() Thread* thread = arena_allocate(global_arena, Thread, 1); thread_init(thread); + mkdir("nest", 0755); + for (u32 i = 0; i < array_length(test_files); i += 1) { File file = { @@ -4744,6 +4640,8 @@ extern "C" void entry_point() .source = file_read(thread->arena, test_files[i]), }; analyze_file(thread, &file); + auto test_dir = string_dir(file.path); + auto test_name = string_base(test_dir); for (u32 function_i = 0; function_i < thread->buffer.functions.length; function_i += 1) { @@ -4761,6 +4659,24 @@ extern "C" void entry_point() auto lowered_source = c_lower(thread); print("Transpiled to C:\n```\n{s}\n```\n", lowered_source); + auto c_source_path = arena_join_string(thread->arena, (Slice(String)) array_to_slice(((String[]) { + strlit("nest/"), + test_name, + strlit(".c"), + }))); + + file_write(c_source_path, lowered_source); + + auto exe_path = s_get_slice(u8, c_source_path, 0, c_source_path.length - 2); + + auto command = arena_join_string(thread->arena, (Slice(String)) array_to_slice(((String[]) { + strlit("clang -g -o "), + exe_path, + strlit(" "), + c_source_path, + }))); + system((char*)command.pointer); + thread_clear(thread); } }