diff --git a/build_test.sh b/build_test.sh index c874c6d..a24449e 100755 --- a/build_test.sh +++ b/build_test.sh @@ -5,5 +5,5 @@ set -xe LLVMC=llvm-config LLVM_LINKER="-lc++ $($LLVMC --libs core --cxxflags --ldflags --system-libs|tr '\n' ' ')" -odin run src -o:none -debug -out:speedcat -extra-linker-flags:"$LLVM_LINKER" -- test_type_checker.cat -clang -I/opt/local/include -L/opt/local/lib -lraylib -lm -framework Cocoa -framework OpenGL -framework IOKit test_type_checker.ll test.c -o raylib +odin run src -o:none -debug -out:speedcat -extra-linker-flags:"$LLVM_LINKER" -- 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 new file mode 100644 index 0000000..0c74cd8 --- /dev/null +++ b/pong.cat @@ -0,0 +1,145 @@ +struct Color { + r g b a: u8, +} + +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 + +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 "poop" +SetTargetFPS 60 + +fn GetScreenWidth i32 +fn GetScreenHeight i32 + +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 { + fc = fc + 1 + 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 { + fc = fc + 1 + if fc / 12 != 0 { + lc = lc + 1 + fc = 0 + } + + if lc >= 10 { + alpha = alpha - 0.02 + if alpha <= 0.0 { + alpha = 0.0 + state = 4 + } + } + } + + BeginDrawing + ClearBackgroundWrap WHITE + if state == 0 { + DrawFPS 20 20 + 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 + + \ DrawText(TextSubtext("raylib", 0, lettersCount), GetScreenWidth()/2 - 44, GetScreenHeight()/2 + 48, 50, Fade(BLACK, alpha)); + \ DrawTextWrap "raylib" GetScreenWidth/2-44 GetScreenHeight/2+48 50 BLACK + } + EndDrawing +} +CloseWindow + +"asf" + diff --git a/src/error.odin b/src/error.odin index a2dfec7..4e9c9d5 100644 --- a/src/error.odin +++ b/src/error.odin @@ -42,7 +42,8 @@ source_print :: proc(data: ^[]u8, range: TextRange) { } else { fmt.printf("%c", ch) } - if pos == range.end { + a := TextPosition{range.end.line, range.end.column - 1} + if pos == a { fmt.printf("\x1B[0m") } } diff --git a/src/lexer.odin b/src/lexer.odin index 76d240d..bdef3d2 100644 --- a/src/lexer.odin +++ b/src/lexer.odin @@ -279,6 +279,7 @@ lexer_read_string :: proc(lexer: ^Lexer, kind: TokenKind, outer: u8) -> Token { lexer_advance(lexer) } crange.range.end = lexer.position + append(&str, 0) return token_create_u8(kind, str, crange) } diff --git a/src/llvm_emitter.odin b/src/llvm_emitter.odin index cf8ff33..21c166d 100644 --- a/src/llvm_emitter.odin +++ b/src/llvm_emitter.odin @@ -11,6 +11,7 @@ LLVMScope :: struct { } g_llvm_scope_stack := [dynamic]LLVMScope{} +g_last_alloca: LLVMValueRef llvm_scope_find_definition :: proc(name: ^[dynamic]u8) -> LLVMValueRef { #reverse for &scope in g_llvm_scope_stack { @@ -66,6 +67,25 @@ generate_llvm :: proc(ctx: LLVMContextRef, mod: LLVMModuleRef, builder: LLVMBuil return fmt.caprintf("scope_%d", scope_num) } + generate_llvm_string :: proc( + ctx: LLVMContextRef, + mod: LLVMModuleRef, + builder: LLVMBuilderRef, + node: ^Node, + ) -> LLVMValueRef { + value := node.value.([dynamic]u8) + str_type := LLVMArrayType(LLVMInt8Type(), u64(len(value))) + str := LLVMAddGlobal(mod, str_type, "str") + LLVMSetInitializer(str, LLVMConstString(cstring(raw_data(value[:])), len(value), 1)) + LLVMSetGlobalConstant(str, 1) + LLVMSetLinkage(str, .PrivateLinkage) + LLVMSetUnnamedAddress(str, .GlobalUnnamedAddr) + LLVMSetAlignment(str, 1) + zi := LLVMConstInt(LLVMInt64Type(), 0, 1) + indexes := [2]LLVMValueRef{zi, zi} + return LLVMBuildInBoundsGEP2(builder, str_type, str, raw_data(indexes[:]), 2, "") + } + generate_llvm_integer :: proc( ctx: LLVMContextRef, mod: LLVMModuleRef, @@ -304,6 +324,8 @@ generate_llvm :: proc(ctx: LLVMContextRef, mod: LLVMModuleRef, builder: LLVMBuil ) -> LLVMValueRef { if node.kind == .Integer { return generate_llvm_integer(ctx, mod, builder, node) + } else if node.kind == .String { + return generate_llvm_string(ctx, mod, builder, node) } else if node.kind == .Float { return generate_llvm_float(ctx, mod, builder, node) } else if node.kind == .FunctionCall { @@ -324,12 +346,17 @@ generate_llvm :: proc(ctx: LLVMContextRef, mod: LLVMModuleRef, builder: LLVMBuil return nil } + struct_value := g_last_alloca + + //struct_value := LLVMBuildAlloca(builder, struct_type, "structini") + //struct_value := LLVMConstNamedStruct(struct_type, raw_data(struct_values[:]), len(struct_values)) struct_values := [dynamic]LLVMValueRef{} for &field, i in node.children[:] { field_value := generate_llvm_expression(ctx, mod, builder, field) + ptr_field := LLVMBuildStructGEP2(builder, struct_type, struct_value, uint(i), "inigep") + LLVMBuildStore(builder, field_value, ptr_field) append(&struct_values, field_value) } - struct_value := LLVMConstNamedStruct(struct_type, raw_data(struct_values[:]), len(struct_values)) return struct_value } else if node.kind == .FieldAccess { if node.children[0].kind == .FieldAccess { @@ -360,6 +387,22 @@ generate_llvm :: proc(ctx: LLVMContextRef, mod: LLVMModuleRef, builder: LLVMBuil fmt.panicf("FIXME: Implement other node kinds. Got: {}", node.kind) } + generate_llvm_bit_cast :: proc( + ctx: LLVMContextRef, + mod: LLVMModuleRef, + builder: LLVMBuilderRef, + node: ^Node, + ) -> LLVMValueRef { + value := generate_llvm_expression(ctx, mod, builder, node.children[0]) + if value == nil { + return nil + } + + type := generate_llvm_type_from_node(ctx, mod, builder, node.return_type) + casted := LLVMBuildBitCast(builder, value, type, "tmpbitcast") + return casted + } + generate_llvm_cast :: proc( ctx: LLVMContextRef, mod: LLVMModuleRef, @@ -372,10 +415,20 @@ generate_llvm :: proc(ctx: LLVMContextRef, mod: LLVMModuleRef, builder: LLVMBuil } if node.return_type.kind == .Integer { if node.children[0].return_type.kind == .Float { - if node.return_type.bit_size == 32 { - return LLVMBuildFPToSI(builder, value, LLVMInt32TypeInContext(ctx), "casttmp") - } else if node.return_type.bit_size == 64 { - return LLVMBuildFPToSI(builder, value, LLVMInt64TypeInContext(ctx), "casttmp") + if node.return_type.is_signed { + return LLVMBuildFPToSI( + builder, + value, + LLVMIntTypeInContext(ctx, uint(node.return_type.bit_size)), + "casttmpsi", + ) + } else { + return LLVMBuildFPToUI( + builder, + value, + LLVMIntTypeInContext(ctx, uint(node.return_type.bit_size)), + "casttmpui", + ) } } else if node.children[0].return_type.kind == .Integer { if node.return_type.is_signed && node.children[0].return_type.is_signed { @@ -442,8 +495,12 @@ generate_llvm :: proc(ctx: LLVMContextRef, mod: LLVMModuleRef, builder: LLVMBuil if node.kind == .Cast { return generate_llvm_cast(ctx, mod, builder, node) } + if node.kind == .BitwiseCast { + return generate_llvm_bit_cast(ctx, mod, builder, node) + } if node.kind == .Integer || node.kind == .Float || + node.kind == .String || node.kind == .FunctionCall || node.kind == .Identifier || node.kind == .StructInitializer || @@ -812,6 +869,8 @@ generate_llvm :: proc(ctx: LLVMContextRef, mod: LLVMModuleRef, builder: LLVMBuil fallthrough case .UnaryExpression: fallthrough + case .String: + fallthrough case .BinaryExpression: generate_llvm_expression(ctx, mod, builder, node) case .VariableDeclaration: @@ -821,9 +880,13 @@ generate_llvm :: proc(ctx: LLVMContextRef, mod: LLVMModuleRef, builder: LLVMBuil type, strings.clone_to_cstring(string(node.children[0].value.([dynamic]u8)[:])), ) + g_last_alloca = var if node.children[2] != nil { value := generate_llvm_expression(ctx, mod, builder, node.children[2]) - LLVMBuildStore(builder, value, var) + // FIXME: Add support for pointers + if LLVMGetTypeKind(LLVMTypeOf(value)) != .LLVMPointerTypeKind { + LLVMBuildStore(builder, value, var) + } } llvm_top_scope().definitions[get_character_sum_of_dyn_arr(&node.children[0].value.([dynamic]u8))] = var llvm_top_scope().types[get_character_sum_of_dyn_arr(&node.children[0].value.([dynamic]u8))] = type diff --git a/src/llvmc.odin b/src/llvmc.odin index 25cfdb6..e0f65b8 100644 --- a/src/llvmc.odin +++ b/src/llvmc.odin @@ -26,6 +26,12 @@ LLVMComdatRef :: distinct rawptr LLVMJITEventListenerRef :: distinct rawptr LLVMBinaryRef :: distinct rawptr +LLVMnnamedAddr :: enum { + NoUnnamedAddr, + LocalUnnamedAddr, + GlobalUnnamedAddr, +} + LLVMTypeKind :: enum { LLVMVoidTypeKind, LLVMHalfTypeKind, @@ -50,6 +56,26 @@ LLVMTypeKind :: enum { LLVMTargetExtTypeKind, } +LLVMLinkage :: enum { + ExternalLinkage, + AvailableExternallyLinkage, + LinkOnceAnyLinkage, + LinkOnceODRLinkage, + LinkOnceODRAutoHideLinkage, + WeakAnyLinkage, + WeakODRLinkage, + AppendingLinkage, + InternalLinkage, + PrivateLinkage, + DLLImportLinkage, + DLLExportLinkage, + ExternalWeakLinkage, + GhostLinkage, + CommonLinkage, + LinkerPrivateLinkage, + LinkerPrivateWeakLinkage, +} + LLVMIntPredicate :: enum { LLVMIntEQ = 32, LLVMIntNE, @@ -100,6 +126,11 @@ foreign llvmc { LLVMBuildRetVoid :: proc(Builder: LLVMBuilderRef) -> LLVMValueRef --- LLVMBuildRet :: proc(Builder: LLVMBuilderRef, V: LLVMValueRef) -> LLVMValueRef --- + LLVMConstString :: proc(Str: cstring, Length: uint, DontNullTerminate: LLVMBool) -> LLVMValueRef --- + LLVMInt8Type :: proc() -> LLVMTypeRef --- + LLVMArrayType :: proc(ElementType: LLVMTypeRef, ElementCount: u64) -> LLVMTypeRef --- + LLVMInt64Type :: proc() -> LLVMTypeRef --- + LLVMInt1TypeInContext :: proc(C: LLVMContextRef) -> LLVMTypeRef --- LLVMInt8TypeInContext :: proc(C: LLVMContextRef) -> LLVMTypeRef --- LLVMInt16TypeInContext :: proc(C: LLVMContextRef) -> LLVMTypeRef --- @@ -175,12 +206,14 @@ foreign llvmc { LLVMBuildPhi :: proc(Builder: LLVMBuilderRef, Ty: LLVMTypeRef, Name: cstring) -> LLVMValueRef --- LLVMBuildFPToSI :: proc(Builder: LLVMBuilderRef, Val: LLVMValueRef, DestTy: LLVMTypeRef, Name: cstring) -> LLVMValueRef --- + LLVMBuildFPToUI :: proc(Builder: LLVMBuilderRef, Val: LLVMValueRef, DestTy: LLVMTypeRef, Name: cstring) -> LLVMValueRef --- LLVMBuildSExt :: proc(Builder: LLVMBuilderRef, Val: LLVMValueRef, DestTy: LLVMTypeRef, Name: cstring) -> LLVMValueRef --- LLVMBuildZExt :: proc(Builder: LLVMBuilderRef, Val: LLVMValueRef, DestTy: LLVMTypeRef, Name: cstring) -> LLVMValueRef --- LLVMBuildIntCast :: proc(Builder: LLVMBuilderRef, Val: LLVMValueRef, DestTy: LLVMTypeRef, Name: cstring) -> LLVMValueRef --- LLVMBuildSIToFP :: proc(Builder: LLVMBuilderRef, Val: LLVMValueRef, DestTy: LLVMTypeRef, Name: cstring) -> LLVMValueRef --- LLVMBuildFPTrunc :: proc(Builder: LLVMBuilderRef, Val: LLVMValueRef, DestTy: LLVMTypeRef, Name: cstring) -> LLVMValueRef --- LLVMBuildFPExt :: proc(Builder: LLVMBuilderRef, Val: LLVMValueRef, DestTy: LLVMTypeRef, Name: cstring) -> LLVMValueRef --- + LLVMBuildBitCast :: proc(Builder: LLVMBuilderRef, Val: LLVMValueRef, DestTy: LLVMTypeRef, Name: cstring) -> LLVMValueRef --- LLVMBuildStructGEP2 :: proc(Builder: LLVMBuilderRef, Ty: LLVMTypeRef, Pointer: LLVMValueRef, Idx: uint, Name: cstring) -> LLVMValueRef --- @@ -196,4 +229,12 @@ foreign llvmc { LLVMSetValueName2 :: proc(Val: LLVMValueRef, Name: cstring, Length: u64) --- LLVMGetReturnType :: proc(Fn: LLVMTypeRef) -> LLVMTypeRef --- + + LLVMAddGlobal :: proc(M: LLVMModuleRef, Ty: LLVMTypeRef, Name: cstring) -> LLVMValueRef --- + LLVMSetInitializer :: proc(GlobalVar: LLVMValueRef, ConstantVal: LLVMValueRef) --- + LLVMSetGlobalConstant :: proc(GlobalVar: LLVMValueRef, Val: LLVMBool) --- + LLVMSetLinkage :: proc(GlobalVar: LLVMValueRef, Linkage: LLVMLinkage) --- + LLVMSetUnnamedAddress :: proc(GlobalVar: LLVMValueRef, UnnamedAddress: LLVMnnamedAddr) --- + LLVMSetAlignment :: proc(GlobalVar: LLVMValueRef, Bytes: uint) --- + LLVMBuildInBoundsGEP2 :: proc(Builder: LLVMBuilderRef, Ty: LLVMTypeRef, Pointer: LLVMValueRef, Indices: [^]LLVMValueRef, NumIndices: uint, Name: cstring) -> LLVMValueRef --- } diff --git a/src/main.odin b/src/main.odin index 5af1a0e..74fa8a5 100644 --- a/src/main.odin +++ b/src/main.odin @@ -44,7 +44,7 @@ main :: proc() { //fmt.printf("%s\n", msg) } if contains_errors { - return + os.exit(1) } } //node_print(ast) @@ -61,7 +61,7 @@ main :: proc() { //fmt.printf("%s\n", msg) } if contains_errors { - return + os.exit(1) } } diff --git a/src/type.odin b/src/type.odin index e53c9a5..0f57b08 100644 --- a/src/type.odin +++ b/src/type.odin @@ -56,7 +56,7 @@ FunctionType :: struct { compare_types :: proc(a: ^Type, b: ^Type) -> (ret: bool, cast_required: bool) { cast_required = false - if (a == nil && b != nil) || (a != nil && b == nil) { + if (a == nil && b != nil) || (a != nil && b == nil) || (a == nil && b == nil) { ret = false return } diff --git a/src/type_checker.odin b/src/type_checker.odin index fc7d9f6..389bfb2 100644 --- a/src/type_checker.odin +++ b/src/type_checker.odin @@ -61,7 +61,7 @@ infer_type :: proc(parent: ^Node, child: ^Node) { case .Float: child.return_type = type_create_float(32) case .String: - child.return_type = type_create_array(type_create_integer(32, false), 0) + child.return_type = type_create_array(type_create_integer(8, false), 0) case .Character: child.return_type = type_create_integer(32, false) } diff --git a/test.c b/test.c deleted file mode 100644 index dd38681..0000000 --- a/test.c +++ /dev/null @@ -1,26 +0,0 @@ -#include - -// void ClearBackground(uint64_t rgba); -// void ClearBackgroundWrap(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { -// ClearBackground((uint64_t)r << 24 | (uint64_t)g << 16 | (uint64_t)b << 8 | -// (uint64_t)a); -// } -// -// void DrawRectangle(uint32_t x, uint32_t y, uint32_t width, uint32_t height, -// uint64_t rgba); -// void DrawRectangleWrap(uint32_t x, uint32_t y, uint32_t width, uint32_t -// height, -// uint8_t r, uint8_t g, uint8_t b, uint8_t a) { -// DrawRectangle(x, y, width, height, -// (uint64_t)r << 24 | (uint64_t)g << 16 | (uint64_t)b << 8 | -// (uint64_t)a); -// } -// -// void DrawCircle(uint32_t x, uint32_t y, float radius, uint64_t rgba); -// void DrawCircleWrap(uint32_t x, uint32_t y, float radius, uint8_t r, uint8_t -// g, -// uint8_t b, uint8_t a) { -// DrawCircle(x, y, radius, -// (uint64_t)r << 24 | (uint64_t)g << 16 | (uint64_t)b << 8 | -// (uint64_t)a); -// }