diff --git a/Makefile b/Makefile index a5a4cdb..4b6642c 100644 --- a/Makefile +++ b/Makefile @@ -2,5 +2,5 @@ LLVMC=llvm-config LLVM_LINKER=-lc++ $(shell ${LLVMC} --libs core --cxxflags --ldflags --system-libs|tr '\n' ' ') all: - odin run src -o:none -debug -out:speedcat -extra-linker-flags:"${LLVM_LINKER}" -- pong.cat && \ + odin run src -o:none -debug -out:speedcat -extra-linker-flags:"${LLVM_LINKER}" -- ${COMP_ARGS} pong.cat && \ clang -I/opt/local/include -L/opt/local/lib -lraylib -lm -framework Cocoa -framework OpenGL -framework IOKit pong.ll -o raylib diff --git a/pong.cat b/pong.cat index 1ec5704..90e4acc 100644 --- a/pong.cat +++ b/pong.cat @@ -1,193 +1,193 @@ -enum MyEnum { - EnumItem1, - EnumItem2 = 1, - EnumItem3, - EnumItem4, -} - -enum MyTypedEnum : i8 { - EnumItem1, - EnumItem2, - EnumItem3 = 105, - EnumItem4, -} +\enum MyEnum { +\ EnumItem1, +\ EnumItem2 = 1, +\ EnumItem3, +\ EnumItem4, +\} +\ +\enum MyTypedEnum : i8 { +\ EnumItem1, +\ EnumItem2, +\ EnumItem3 = 105, +\ EnumItem4, +\} struct Vec2 { x y: f32, } -\struct Rect { -\ pos size: Vec2, -\} -\ +struct Rect { + pos size: Vec2, +} + let CONSTPOS :: .Vec2 {20.0 20.0} -\let CONSTSZ :: .Vec2 {100.0 100.0} -\let CONST :: .Rect {(CONSTPOS) (CONSTSZ)} -\ -\\ FIXME: LLVM IR geneartion is borked -\\ let CONST :: .Rect { .Vec2 { 20.0 20.0 } .Vec2 { 100.0 100.0 } } -\ -\struct Color { -\ r g b a: u8, -\} -\ -\let KEY_R :: 82 -\ -\fn InitWindow(w h: i32, title: []u8) -\fn CloseWindow -\fn BeginDrawing -\fn SetTargetFPS(fps: i32) -\fn EndDrawing -\fn DrawFPS(x y: i32) -\fn WindowShouldClose i32 -\fn TextSubtext(text: []u8, start end: i32) []u8 -\fn IsKeyPressed(key: i32) u1 -\ -\struct Rectangle { -\ x y w h: f32, -\} -\ -\fn ColorToRaylib(c: Color) u32 { -\ ret c.a as u32 << 24 as u32 | c.b as u32 << 16 as u32 | c.g as u32 << 8 as u32 | c.r -\} -\ -\fn ClearBackgroundWrap(c: Color) { -\ fn ClearBackground(c: u32) -\ ClearBackground (ColorToRaylib c) -\} -\ -\fn DrawRectangleWrap(x y w h: i32, c: Color) { -\ fn DrawRectangle(x y w h: i32, c: u32) -\ DrawRectangle x y w h (ColorToRaylib c) -\} -\ -\fn DrawCircleWrap(x y: i32, r: f32, c: Color) { -\ fn DrawCircle(x y: i32, r: f32, c: u32) -\ DrawCircle x y r (ColorToRaylib c) -\} -\ -\fn DrawRectangleRecWrap(r: Rectangle, c: Color) { -\ fn DrawRectangleRec(r: Rectangle, c: u32) -\ DrawRectangleRec r (ColorToRaylib c) -\} -\ -\fn DrawTextWrap(text: []u8, x y size: i32, c: Color) { -\ fn DrawText(text: []u8, x y size: i32, c: u32) -\ DrawText text x y size (ColorToRaylib c) -\} -\ -\let WHITE :: .Color {255 255 255 255} -\let BLACK :: .Color {0 0 0 255} -\let RED :: .Color {255 0 0 255} -\let BLUE :: .Color {0 0 255 255} -\ -\InitWindow 800 450 Raylib -\SetTargetFPS 60 -\ -\fn GetScreenWidth i32 -\fn GetScreenHeight i32 -\ -\fn DrawRect(rect: Rect, c: Color) { -\ DrawRectangleWrap (rect.pos.x as i32) (rect.pos.y as i32) (rect.size.x as i32) (rect.size.y as i32) c -\} -\ -\let logox := GetScreenWidth / 2 - 128 -\let logoy := GetScreenHeight / 2 - 128 -\ -\\ FIXME: Cannot inline -\let fc := 0 -\let lc := 0 -\let top_side_rec_width := 16 -\let left_side_rec_height := 16 -\let bottom_side_rec_width := 16 -\let right_side_rec_height := 16 -\ -\let state := 0 -\let alpha := 1.0 -\ -\for WindowShouldClose == 0 { -\ if state == 0 { -\ if ++fc == 120 { -\ state = 1 -\ fc = 0 -\ } -\ } elif state == 1 { -\ top_side_rec_width = top_side_rec_width + 4 -\ left_side_rec_height = left_side_rec_height + 4 -\ -\ if top_side_rec_width == 256 { -\ state = 2 -\ } -\ } elif state == 2 { -\ bottom_side_rec_width = bottom_side_rec_width + 4 -\ right_side_rec_height = right_side_rec_height + 4 -\ -\ if bottom_side_rec_width == 256 { -\ state = 3 -\ } -\ } elif state == 3 { -\ if ++fc / 12 != 0 { -\ ++lc -\ fc = 0 -\ } -\ -\ if lc >= 10 { -\ alpha = alpha - 0.01 -\ if alpha <= 0.0 { -\ alpha = 0.0 -\ state = 4 -\ } -\ } -\ } elif IsKeyPressed(KEY_R) { \ -\ fc = lc = 0 -\ -\ top_side_rec_width = 16 -\ left_side_rec_height = 16 -\ bottom_side_rec_width = 16 -\ right_side_rec_height = 16 -\ -\ state = 0 -\ alpha = 1.0 -\ } -\ -\ BeginDrawing -\ ClearBackgroundWrap WHITE -\ DrawFPS 20 20 -\ -\ DrawRect CONST RED -\ -\ if state == 0 { -\ if (fc/15)%2 != 0 { -\ DrawRectangleWrap logox logoy 16 16 BLACK -\ } -\ } elif state == 1 { -\ DrawRectangleWrap logox logoy top_side_rec_width 16 BLACK -\ DrawRectangleWrap logox logoy 16 left_side_rec_height BLACK -\ } elif state == 2 { -\ DrawRectangleWrap logox logoy top_side_rec_width 16 BLACK -\ DrawRectangleWrap logox logoy 16 left_side_rec_height BLACK -\ -\ DrawRectangleWrap logox+240 logoy 16 right_side_rec_height BLACK -\ DrawRectangleWrap logox logoy+240 bottom_side_rec_width 16 BLACK -\ } elif state == 3 { -\ let colorw := .Color{255 255 255 (alpha*255.0) as u8} -\ let colorb := .Color{0 0 0 (alpha*255.0) as u8} -\ \ FIXME: ADD field access assignment -\ \color.a = (alpha * 255.0) as u8 -\ DrawRectangleWrap logox logoy top_side_rec_width 16 colorb -\ DrawRectangleWrap logox logoy+16 16 left_side_rec_height-32 colorb -\ -\ DrawRectangleWrap logox+240 logoy+16 16 right_side_rec_height-32 cbolor -\ DrawRectangleWrap logox logoy+240 bottom_side_rec_width 16 colorb -\ -\ DrawRectangleWrap GetScreenWidth/2-112 GetScreenHeight/2-112 224 224 colorw -\ -\ DrawTextWrap (TextSubtext raylib 0 lc) GetScreenWidth/2-44 GetScreenHeight/2+48 50 colorb -\ } else { -\ DrawTextWrap "[R] REPLAY" 340 200 20 BLACK -\ } -\ -\ EndDrawing -\} -\CloseWindow -\ +let CONSTSZ :: .Vec2 {100.0 100.0} +let CONST :: .Rect {(CONSTPOS) (CONSTSZ)} + +\ FIXME: LLVM IR geneartion is borked +\ let CONST :: .Rect { .Vec2 { 20.0 20.0 } .Vec2 { 100.0 100.0 } } + +struct Color { + r g b a: u8, +} + +let KEY_R :: 82 + +fn InitWindow(w h: i32, title: []u8) +fn CloseWindow +fn BeginDrawing +fn SetTargetFPS(fps: i32) +fn EndDrawing +fn DrawFPS(x y: i32) +fn WindowShouldClose i32 +fn TextSubtext(text: []u8, start end: i32) []u8 +fn IsKeyPressed(key: i32) u1 + +struct Rectangle { + x y w h: f32, +} + +fn ColorToRaylib(c: Color) u32 { + ret c.a as u32 << 24 as u32 | c.b as u32 << 16 as u32 | c.g as u32 << 8 as u32 | c.r +} + +fn ClearBackgroundWrap(c: Color) { + fn ClearBackground(c: u32) + ClearBackground (ColorToRaylib c) +} + +fn DrawRectangleWrap(x y w h: i32, c: Color) { + fn DrawRectangle(x y w h: i32, c: u32) + DrawRectangle x y w h (ColorToRaylib c) +} + +fn DrawCircleWrap(x y: i32, r: f32, c: Color) { + fn DrawCircle(x y: i32, r: f32, c: u32) + DrawCircle x y r (ColorToRaylib c) +} + +fn DrawRectangleRecWrap(r: Rectangle, c: Color) { + fn DrawRectangleRec(r: Rectangle, c: u32) + DrawRectangleRec r (ColorToRaylib c) +} + +fn DrawTextWrap(text: []u8, x y size: i32, c: Color) { + fn DrawText(text: []u8, x y size: i32, c: u32) + DrawText text x y size (ColorToRaylib c) +} + +let WHITE :: .Color {255 255 255 255} +let BLACK :: .Color {0 0 0 255} +let RED :: .Color {255 0 0 255} +let BLUE :: .Color {0 0 255 255} + +InitWindow 800 450 Raylib +SetTargetFPS 60 + +fn GetScreenWidth i32 +fn GetScreenHeight i32 + +fn DrawRect(rect: Rect, c: Color) { + DrawRectangleWrap (rect.pos.x as i32) (rect.pos.y as i32) (rect.size.x as i32) (rect.size.y as i32) c +} + +let logox := GetScreenWidth / 2 - 128 +let logoy := GetScreenHeight / 2 - 128 + +\ FIXME: Cannot inline +let fc := 0 +let lc := 0 +let top_side_rec_width := 16 +let left_side_rec_height := 16 +let bottom_side_rec_width := 16 +let right_side_rec_height := 16 + +let state := 0 +let alpha := 1.0 + +for WindowShouldClose == 0 { + if state == 0 { + if ++fc == 120 { + state = 1 + fc = 0 + } + } elif state == 1 { + top_side_rec_width = top_side_rec_width + 4 + left_side_rec_height = left_side_rec_height + 4 + + if top_side_rec_width == 256 { + state = 2 + } + } elif state == 2 { + bottom_side_rec_width = bottom_side_rec_width + 4 + right_side_rec_height = right_side_rec_height + 4 + + if bottom_side_rec_width == 256 { + state = 3 + } + } elif state == 3 { + if ++fc / 12 != 0 { + ++lc + fc = 0 + } + + if lc >= 10 { + alpha = alpha - 0.01 + if alpha <= 0.0 { + alpha = 0.0 + state = 4 + } + } + } elif IsKeyPressed(KEY_R) { \ + fc = lc = 0 + + top_side_rec_width = 16 + left_side_rec_height = 16 + bottom_side_rec_width = 16 + right_side_rec_height = 16 + + state = 0 + alpha = 1.0 + } + + BeginDrawing + ClearBackgroundWrap WHITE + DrawFPS 20 20 + + DrawRect CONST RED + + if state == 0 { + if (fc/15)%2 != 0 { + DrawRectangleWrap logox logoy 16 16 BLACK + } + } elif state == 1 { + DrawRectangleWrap logox logoy top_side_rec_width 16 BLACK + DrawRectangleWrap logox logoy 16 left_side_rec_height BLACK + } elif state == 2 { + DrawRectangleWrap logox logoy top_side_rec_width 16 BLACK + DrawRectangleWrap logox logoy 16 left_side_rec_height BLACK + + DrawRectangleWrap logox+240 logoy 16 right_side_rec_height BLACK + DrawRectangleWrap logox logoy+240 bottom_side_rec_width 16 BLACK + } elif state == 3 { + let colorw := .Color{255 255 255 (alpha*255.0) as u8} + let colorb := .Color{0 0 0 (alpha*255.0) as u8} + \ FIXME: ADD field access assignment + \color.a = (alpha * 255.0) as u8 + DrawRectangleWrap logox logoy top_side_rec_width 16 colorb + DrawRectangleWrap logox logoy+16 16 left_side_rec_height-32 colorb + + DrawRectangleWrap logox+240 logoy+16 16 right_side_rec_height-32 cbolor + DrawRectangleWrap logox logoy+240 bottom_side_rec_width 16 colorb + + DrawRectangleWrap GetScreenWidth/2-112 GetScreenHeight/2-112 224 224 colorw + + DrawTextWrap (TextSubtext raylib 0 lc) GetScreenWidth/2-44 GetScreenHeight/2+48 50 colorb + } else { + DrawTextWrap "[R] REPLAY" 340 200 20 BLACK + } + + EndDrawing +} +CloseWindow + diff --git a/src/argparser.odin b/src/argparser.odin new file mode 100644 index 0000000..c9e80ec --- /dev/null +++ b/src/argparser.odin @@ -0,0 +1,52 @@ +package main + +Options :: struct { + file: string, + dump_ast: bool, + dont_emit_llvm: bool, +} + +parse_args :: proc(args: ^[]string) -> (o: Options) { + o.file = "" + o.dump_ast = false + o.dont_emit_llvm = false + + for &arg, idx in args^ { + if idx == 0 { + continue + } + + if len(arg) <= 1 { + continue + } + + if arg[0] == '-' && arg[1] != '-' { + for ch, idx in arg { + if idx == 0 { + continue + } + + switch (ch) { + case 'd': + o.dump_ast = true + case 'L': + o.dont_emit_llvm = true + case: + panic("Invalid command line switch") + } + } + } else if arg[0] == '-' && arg[1] == '-' { + switch (arg) { + case "--dump-ast": + o.dump_ast = true + case "--dont-emit-llvm": + o.dont_emit_llvm = true + case: + panic("Invalid command line switch") + } + } else { + o.file = arg + } + } + return +} diff --git a/src/main.odin b/src/main.odin index ee727ba..58bd90b 100644 --- a/src/main.odin +++ b/src/main.odin @@ -5,16 +5,19 @@ import "core:os" import "core:time" main :: proc() { + fmt.println("Speedcat bootstrap compiler") + fmt.println("===========================") + handle: os.Handle - file_name := "" - if len(os.args) >= 2 { + options := parse_args(&os.args) + file_name := options.file + if file_name != "" { errno: os.Errno - handle, errno = os.open(os.args[1]) + handle, errno = os.open(file_name) if errno != 0 { fmt.printf("Error opening file\n", errno) return } - file_name = os.args[1] } else { handle = os.stdin } @@ -37,7 +40,6 @@ main :: proc() { parser_time_start := time.now() ast := parser_parse(&parser) parser_duration := time.since(parser_time_start) - defer fmt.printf("Parsing took: {}ns\n", time.duration_nanoseconds(parser_duration)) if len(g_message_list) > 0 { contains_errors := false @@ -56,7 +58,6 @@ main :: proc() { type_check_start := time.now() type_check(ast, nil) type_check_duration := time.since(type_check_start) - defer fmt.printf("Type checker took: {}ns\n", time.duration_nanoseconds(type_check_duration)) if len(g_message_list) > 0 { contains_errors := false @@ -71,39 +72,80 @@ main :: proc() { } } - node_print(ast) + if options.dump_ast { + 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) + 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) { diff --git a/src/type_checker.odin b/src/type_checker.odin index 543d3c4..8fc6d96 100644 --- a/src/type_checker.odin +++ b/src/type_checker.odin @@ -675,8 +675,6 @@ type_check :: proc(ast: ^Node, parent_ast: ^Node) { type_check(child, ast) } - node_print(ast) - struct_ := find_struct(ast.value.([dynamic]u8)) if struct_ == nil { append( @@ -704,7 +702,6 @@ type_check :: proc(ast: ^Node, parent_ast: ^Node) { idx := 0 for &child in ast.children { - fmt.printf("Comp {} and {} (struct f)\n", child.return_type.kind, struct_.fields[idx].type.kind) ok, cast_required := compare_types(child.return_type, struct_.fields[idx].type) if cast_required { cast_ := node_create_cast({}, child, {})