Add some support for recursive structs
Signed-off-by: Slendi <slendi@socopon.com>
This commit is contained in:
parent
c5747a103e
commit
b170e9a424
29
pong.cat
29
pong.cat
@ -1,3 +1,18 @@
|
||||
struct Vec2 {
|
||||
x y: f32,
|
||||
}
|
||||
|
||||
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,
|
||||
}
|
||||
@ -47,10 +62,10 @@ fn DrawTextWrap(text: []u8, x y size: i32, c: Color) {
|
||||
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}
|
||||
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
|
||||
@ -58,6 +73,10 @@ 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
|
||||
|
||||
@ -121,6 +140,8 @@ for WindowShouldClose == 0 {
|
||||
ClearBackgroundWrap WHITE
|
||||
DrawFPS 20 20
|
||||
|
||||
DrawRect CONST RED
|
||||
|
||||
if state == 0 {
|
||||
if (fc/15)%2 != 0 {
|
||||
DrawRectangleWrap logox logoy 16 16 BLACK
|
||||
|
@ -325,20 +325,23 @@ generate_llvm :: proc(ctx: LLVMContextRef, mod: LLVMModuleRef, builder: LLVMBuil
|
||||
mod: LLVMModuleRef,
|
||||
builder: LLVMBuilderRef,
|
||||
node: ^Node,
|
||||
) -> LLVMValueRef {
|
||||
) -> (
|
||||
LLVMValueRef,
|
||||
LLVMValueRef,
|
||||
) {
|
||||
if node.kind == .Integer {
|
||||
return generate_llvm_integer(ctx, mod, builder, node)
|
||||
return generate_llvm_integer(ctx, mod, builder, node), nil
|
||||
} else if node.kind == .String {
|
||||
return generate_llvm_string(ctx, mod, builder, node)
|
||||
return generate_llvm_string(ctx, mod, builder, node), nil
|
||||
} else if node.kind == .Float {
|
||||
return generate_llvm_float(ctx, mod, builder, node)
|
||||
return generate_llvm_float(ctx, mod, builder, node), nil
|
||||
} else if node.kind == .FunctionCall {
|
||||
return generate_llvm_function_call(ctx, mod, builder, node)
|
||||
return generate_llvm_function_call(ctx, mod, builder, node), nil
|
||||
} else if node.kind == .Identifier {
|
||||
def := llvm_scope_find_definition(&node.value.([dynamic]u8))
|
||||
type := llvm_scope_find_type(&node.value.([dynamic]u8))
|
||||
def_value := LLVMBuildLoad2(builder, type, def, "loadtmp")
|
||||
return def_value
|
||||
return def_value, nil
|
||||
} else if node.kind == .StructInitializer {
|
||||
struct_name := &node.value.([dynamic]u8)
|
||||
struct_type := llvm_scope_find_type(struct_name)
|
||||
@ -347,30 +350,44 @@ generate_llvm :: proc(ctx: LLVMContextRef, mod: LLVMModuleRef, builder: LLVMBuil
|
||||
&g_message_list,
|
||||
message_create(.Error, fmt.aprintf("Struct '%s' not found", struct_name), node.range),
|
||||
)
|
||||
return nil
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
struct_value := g_last_alloca
|
||||
|
||||
struct_values := [dynamic]LLVMValueRef{}
|
||||
for &field, i in node.children[:] {
|
||||
last_alloc_a := g_last_alloca
|
||||
field_value := generate_llvm_expression(ctx, mod, builder, field)
|
||||
g_last_alloca = last_alloc_a
|
||||
ptr_field := LLVMBuildStructGEP2(builder, struct_type, struct_value, uint(i), "inigep")
|
||||
LLVMBuildStore(builder, field_value, ptr_field)
|
||||
append(&struct_values, field_value)
|
||||
}
|
||||
return struct_value
|
||||
return struct_value, nil
|
||||
} else if node.kind == .FieldAccess {
|
||||
struct_name: ^[dynamic]u8
|
||||
struct_value: LLVMValueRef
|
||||
if node.children[0].kind == .FieldAccess {
|
||||
append(
|
||||
&g_message_list,
|
||||
message_create(.FIXME, fmt.aprintf("Nested field accesses are not implemented."), node.range),
|
||||
)
|
||||
return nil
|
||||
struct_name = &node.children[0].return_type.struct_type.name
|
||||
_, struct_value = generate_llvm_value(ctx, mod, builder, node.children[0])
|
||||
} else if node.children[0].kind == .Identifier {
|
||||
struct_name = &node.children[0].value.([dynamic]u8)
|
||||
} else {
|
||||
panic("LLVM: Invalid LHS")
|
||||
}
|
||||
|
||||
type_struct := llvm_scope_find_type(struct_name)
|
||||
if type_struct == nil {
|
||||
fmt.println("Unable to find struct type definition")
|
||||
}
|
||||
|
||||
def_struct := llvm_scope_find_definition(struct_name)
|
||||
if struct_value != nil {
|
||||
def_struct = struct_value
|
||||
}
|
||||
if def_struct == nil {
|
||||
fmt.println("Unable to find struct definition")
|
||||
}
|
||||
|
||||
def_struct := llvm_scope_find_definition(&node.children[0].value.([dynamic]u8))
|
||||
type_struct := llvm_scope_find_type(&node.children[0].value.([dynamic]u8))
|
||||
type_ref := generate_llvm_type_from_node(ctx, mod, builder, node.return_type)
|
||||
struct_field_data := LLVMBuildAlloca(builder, type_ref, "struct_field")
|
||||
|
||||
@ -383,7 +400,7 @@ generate_llvm :: proc(ctx: LLVMContextRef, mod: LLVMModuleRef, builder: LLVMBuil
|
||||
)
|
||||
def_value := LLVMBuildLoad2(builder, type_ref, def, "loadtmp")
|
||||
|
||||
return def_value
|
||||
return def_value, def
|
||||
}
|
||||
|
||||
fmt.panicf("FIXME: Implement other node kinds. Got: {}", node.kind)
|
||||
@ -507,7 +524,8 @@ generate_llvm :: proc(ctx: LLVMContextRef, mod: LLVMModuleRef, builder: LLVMBuil
|
||||
node.kind == .Identifier ||
|
||||
node.kind == .StructInitializer ||
|
||||
node.kind == .FieldAccess {
|
||||
return generate_llvm_value(ctx, mod, builder, node)
|
||||
v, _ := generate_llvm_value(ctx, mod, builder, node)
|
||||
return v
|
||||
}
|
||||
if node.kind == .FunctionCall {
|
||||
return generate_llvm_function_call(ctx, mod, builder, node)
|
||||
|
@ -61,6 +61,19 @@ compare_types :: proc(a: ^Type, b: ^Type) -> (ret: bool, cast_required: bool) {
|
||||
return
|
||||
}
|
||||
|
||||
if (a.kind == .Struct && b.kind != .Struct) {
|
||||
return false, false
|
||||
}
|
||||
if (a.kind != .Struct && b.kind == .Struct) {
|
||||
return false, false
|
||||
}
|
||||
if (a.kind == .Struct && b.kind == .Struct) {
|
||||
if (compare_dyn_arrs(&a.struct_type.name, &b.struct_type.name)) {
|
||||
return true, false
|
||||
}
|
||||
return false, false
|
||||
}
|
||||
|
||||
if (a.kind == .Integer || a.kind == .Float) && (a.bit_size > b.bit_size) {
|
||||
ret = true
|
||||
cast_required = true
|
||||
|
@ -268,22 +268,19 @@ type_check :: proc(ast: ^Node, parent_ast: ^Node) {
|
||||
if rhs.kind != .Identifier {
|
||||
append(
|
||||
&g_message_list,
|
||||
message_create(.Error, fmt.aprintf("Field access rhs is not an identifier or field access: {}", rhs.kind), rhs.range),
|
||||
)
|
||||
message_create(
|
||||
.Error,
|
||||
fmt.aprintf("Field access rhs is not an identifier or field access: {}", rhs.kind),
|
||||
rhs.range,
|
||||
),
|
||||
)
|
||||
break
|
||||
}
|
||||
|
||||
if lhs.kind == .FieldAccess {
|
||||
type_check(lhs, ast)
|
||||
if lhs.return_type.kind != .Struct {
|
||||
append(
|
||||
&g_message_list,
|
||||
message_create(
|
||||
.Error,
|
||||
fmt.aprintf("LHS is not a Struct type"),
|
||||
lhs.range,
|
||||
),
|
||||
)
|
||||
append(&g_message_list, message_create(.Error, fmt.aprintf("LHS is not a Struct type"), lhs.range))
|
||||
}
|
||||
|
||||
struct_ = scope_struct_lookup(lhs.return_type.struct_type.name)
|
||||
@ -308,9 +305,7 @@ type_check :: proc(ast: ^Node, parent_ast: ^Node) {
|
||||
|
||||
struct_index: u64 = 0
|
||||
found_field := false
|
||||
fmt.println("==")
|
||||
for &field, i in struct_.fields {
|
||||
fmt.printf("- %s\n", field.name)
|
||||
if compare_dyn_arrs(&field.name, &rhs.value.([dynamic]u8)) {
|
||||
ast.return_type = field.type
|
||||
found_field = true
|
||||
@ -347,17 +342,13 @@ type_check :: proc(ast: ^Node, parent_ast: ^Node) {
|
||||
|
||||
type := scope_variable_lookup(ast.children[0].value.([dynamic]u8))
|
||||
if type != nil {
|
||||
if len(ast.children) != 1 {
|
||||
append(&g_message_list, message_create(.Error, "Variable is not a function", ast.range))
|
||||
break
|
||||
}
|
||||
|
||||
name := ast.children[0].value.([dynamic]u8)
|
||||
free(ast.children[0])
|
||||
clear(&ast.children)
|
||||
ast.return_type = type
|
||||
ast.kind = .Identifier
|
||||
ast.value = name
|
||||
type_check(ast, parent_ast)
|
||||
} else {
|
||||
fn := type_check_function_call(ast, parent_ast)
|
||||
if fn != nil {
|
||||
@ -394,8 +385,8 @@ type_check :: proc(ast: ^Node, parent_ast: ^Node) {
|
||||
fmt.aprintf(
|
||||
"Type mismatch in function call for `%s`: Wanted {}, got {}",
|
||||
fn.name,
|
||||
param,
|
||||
ast.children[i + 1].return_type,
|
||||
type_to_string(param),
|
||||
type_to_string(ast.children[i + 1].return_type),
|
||||
),
|
||||
ast.range,
|
||||
),
|
||||
@ -467,11 +458,11 @@ type_check :: proc(ast: ^Node, parent_ast: ^Node) {
|
||||
)
|
||||
}
|
||||
} else if ast.value_token_kind == .Equals ||
|
||||
ast.value_token_kind == .NotEquals ||
|
||||
ast.value_token_kind == .GreaterThan ||
|
||||
ast.value_token_kind == .GreaterThanOrEqual ||
|
||||
ast.value_token_kind == .LessThan ||
|
||||
ast.value_token_kind == .LessThanOrEqual {
|
||||
ast.value_token_kind == .NotEquals ||
|
||||
ast.value_token_kind == .GreaterThan ||
|
||||
ast.value_token_kind == .GreaterThanOrEqual ||
|
||||
ast.value_token_kind == .LessThan ||
|
||||
ast.value_token_kind == .LessThanOrEqual {
|
||||
ast.return_type = type_create_integer(1, true)
|
||||
}
|
||||
// FIXME: Verify that the operation is possible
|
||||
@ -670,6 +661,8 @@ 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(
|
||||
@ -697,6 +690,7 @@ 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, {})
|
||||
@ -710,10 +704,10 @@ type_check :: proc(ast: ^Node, parent_ast: ^Node) {
|
||||
.Error,
|
||||
fmt.aprintf(
|
||||
"Type mismatch in struct initializer: Wanted {}, got {}",
|
||||
struct_.fields[idx].type,
|
||||
child.return_type,
|
||||
type_to_string(struct_.fields[idx].type),
|
||||
type_to_string(child.return_type),
|
||||
),
|
||||
ast.range,
|
||||
child.range,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user