From 00ab96818e8bb001ed26ee09adc1e3e230b03631 Mon Sep 17 00:00:00 2001 From: Baitinq Date: Sun, 13 Jul 2025 22:33:17 +0200 Subject: Boostrap: Support struct field access assignment --- src/bootstrap/codegen.pry | 96 +++++++++++++++++++++++++++++++++++++++++++++++ src/bootstrap/llvm.pry | 1 + src/bootstrap/parser.pry | 32 ++++++++++++++++ 3 files changed, 129 insertions(+) diff --git a/src/bootstrap/codegen.pry b/src/bootstrap/codegen.pry index 858ebfa..fa75af3 100644 --- a/src/bootstrap/codegen.pry +++ b/src/bootstrap/codegen.pry @@ -805,6 +805,88 @@ let codegen_generate_expression_value = (c: *codegen, expression: *Node, name: * return cast(*Variable, null); }; +let StructField = struct { + value: LLVMValueRef, + type: *Node, +}; + +let codegen_get_struct_field = (c: *codegen, node: *Node, name: *i8) => *StructField { + let ptr = cast(*Variable, null); + if (*node).type == NODE_PRIMARY_EXPRESSION_IDENTIFIER { + let identifier = *cast(*NODE_PRIMARY_EXPRESSION_IDENTIFIER_DATA, (*node).data); + ptr = environment_get_variable((*c).environment, identifier.name); + }; + if (*node).type == NODE_UNARY_EXPRESSION { + let xd = (*cast(*NODE_UNARY_EXPRESSION_DATA, (*node).data)).expression; + ptr = codegen_generate_expression_value(c, xd, ""); + }; + + assert(ptr != cast(*Variable, null)); + + let typ = cast(*Node, null); + let ptr_typ = (*ptr).node_type; + if (*ptr_typ).type == NODE_TYPE_STRUCT_TYPE { + typ = ptr_typ; + }; + if (*ptr_typ).type == NODE_TYPE_POINTER_TYPE { + let pt = *cast(*NODE_TYPE_POINTER_TYPE_DATA, (*ptr_typ).data); + let pt_type = pt.type; + assert((*pt_type).type == NODE_TYPE_SIMPLE_TYPE); + let simple_type = *cast(*NODE_TYPE_SIMPLE_TYPE_DATA, (*pt_type).data); + let v = environment_get_variable((*c).environment, simple_type.name); + assert(v != cast(*Variable, null)); + typ = (*v).node_type; + }; + if (*ptr_typ).type == NODE_TYPE_SIMPLE_TYPE { + let simple_type = *cast(*NODE_TYPE_SIMPLE_TYPE_DATA, (*ptr_typ).data); + let v = environment_get_variable((*c).environment, simple_type.name); + assert(v != cast(*Variable, null)); + typ = (*v).node_type; + }; + + assert(typ != cast(*Node, null)); + assert((*typ).type == NODE_TYPE_SIMPLE_TYPE); + let simple_type = *cast(*NODE_TYPE_SIMPLE_TYPE_DATA, (*typ).data); + assert((*simple_type.underlying_type).type == NODE_TYPE_STRUCT_TYPE); + let struc_type = *cast(*NODE_TYPE_STRUCT_TYPE_DATA, (*simple_type.underlying_type).data); + + let fieldIndex = cast(*i64, null); + + let i = 0; + while i < struc_type.fields_len { + let field = *(struc_type.fields + cast(**Node, i)); + assert((*field).type == NODE_PRIMARY_EXPRESSION_IDENTIFIER); + let field_data = *cast(*NODE_PRIMARY_EXPRESSION_IDENTIFIER_DATA, (*field).data); + if strcmp(name, field_data.name) { + let ii = cast(*i64, arena_alloc((*c).arena, sizeof(i64))); + *ii = i; + fieldIndex = ii; + break; + }; + i = i + 1; + }; + + assert(fieldIndex != cast(*i64, null)); + + let zero = LLVMConstInt(LLVMInt32Type(), 0, 0); + let llvmFieldIndex = LLVMConstInt(LLVMInt32Type(), *fieldIndex, 0); + let indices = cast(*LLVMValueRef, arena_alloc((*c).arena, sizeof(LLVMValueRef) * 2)); + (*(indices + cast(*LLVMValueRef, 0))) = zero; + (*(indices + cast(*LLVMValueRef, 1))) = llvmFieldIndex; + + let res = cast(*StructField, arena_alloc((*c).arena, sizeof(StructField))); + + let x = codegen_get_llvm_type(c, typ); + assert(x != cast(*LLVMTypeRef, null)); + (*res).value = LLVMBuildGEP2((*c).builder, *x, (*ptr).value, indices, 2, name); + let no = *(struc_type.fields + cast(**Node, *fieldIndex)); + assert((*no).type == NODE_PRIMARY_EXPRESSION_IDENTIFIER); + let no_d = *cast(*NODE_PRIMARY_EXPRESSION_IDENTIFIER_DATA, (*no).data); + (*res).type = no_d.type; + + return res; +}; + let codegen_generate_assignment_statement = (c: *codegen, stmt: *NODE_ASSIGNMENT_STATEMENT_DATA) => i64 { let lhs = *((*stmt).lhs); let prhs = (*stmt).rhs; @@ -886,6 +968,20 @@ let codegen_generate_assignment_statement = (c: *codegen, stmt: *NODE_ASSIGNMENT return 0; }; + + if (lhs.type == NODE_FIELD_ACCESS) { + let field_access = (*cast(*NODE_FIELD_ACCESS_DATA, lhs.data)); + let xd = field_access.expression; + let name = field_access.name; + + let x = codegen_get_struct_field(c, xd, name); + + let variable = codegen_generate_expression_value(c, prhs, cast(*i8, null)); + /* TODO: Typecheck */ + LLVMBuildStore((*c).builder, (*variable).value, (*x).value); + + return 0; + }; printf("ASSERT 2 %d\n", lhs.type); assert(false); diff --git a/src/bootstrap/llvm.pry b/src/bootstrap/llvm.pry index 84ce88c..9b0e150 100644 --- a/src/bootstrap/llvm.pry +++ b/src/bootstrap/llvm.pry @@ -266,6 +266,7 @@ let LLVMBasicBlockRef = newtype *void; extern LLVMGetModuleDataLayout = (LLVMModuleRef) => LLVMTargetDataRef; extern LLVMConstInt = (LLVMTypeRef, i64, i64) => LLVMValueRef; extern LLVMInt64Type = () => LLVMTypeRef; +extern LLVMInt32Type = () => LLVMTypeRef; extern LLVMInt1Type = () => LLVMTypeRef; extern LLVMInt8Type = () => LLVMTypeRef; extern LLVMVoidType = () => LLVMTypeRef; diff --git a/src/bootstrap/parser.pry b/src/bootstrap/parser.pry index 658d1f9..155244f 100644 --- a/src/bootstrap/parser.pry +++ b/src/bootstrap/parser.pry @@ -732,6 +732,7 @@ let parser_parse_function_definition = (p: *parser) => *Node { return create_node(p, n); }; +/* StructInstantiation ::= IDENTIFIER LBRACE RBRACE */ let parser_parse_struct_instanciation = (p: *parser) => *Node { let typ = parser_accept_token(p, TOKEN_IDENTIFIER); if typ == cast(*token, null) { @@ -755,6 +756,33 @@ let parser_parse_struct_instanciation = (p: *parser) => *Node { return create_node(p, n); }; +extern parser_parse_primary_expression = (*parser) => *Node; + +/* FieldAccess ::= PrimaryExpression DOT IDENTIFIER */ +let parser_parse_field_access = (p: *parser) => *Node { + let expression = parser_parse_primary_expression(p); + if expression == cast(*Node, null) { + return cast(*Node, null); + }; + if parser_accept_token(p, TOKEN_DOT) == cast(*token, null) { + return cast(*Node, null); + }; + let ident = parser_accept_token(p, TOKEN_IDENTIFIER); + if ident == cast(*token, null) { + return cast(*Node, null); + }; + + let d = cast(*NODE_FIELD_ACCESS_DATA, arena_alloc((*p).arena, sizeof(NODE_FIELD_ACCESS_DATA))); + (*d).expression = expression; + (*d).name = cast(*i8, (*ident).data); + + let n = Node{}; + n.type = NODE_FIELD_ACCESS; + n.data = cast(*void, d); + + return create_node(p, n); +}; + /* PrimaryExpression ::= NULL | NUMBER | BOOLEAN | CHAR | STRING | IDENTIFIER | FunctionDefinition | StructDefinition | StructInstantiation | FieldAccess | LPAREN Expression RPAREN */ let parser_parse_primary_expression = (p: *parser) => *Node { let stmt = parser_accept_parse(p, parser_parse_function_definition); @@ -953,6 +981,10 @@ let parser_parse_postfix_expression = (p: *parser) => *Node { if ex != cast(*Node, null) { return ex; }; + let ex = parser_accept_parse(p, parser_parse_field_access); + if ex != cast(*Node, null) { + return ex; + }; return parser_parse_primary_expression(p); }; -- cgit 1.4.1