diff options
| author | Baitinq <[email protected]> | 2025-05-27 19:51:27 +0200 |
|---|---|---|
| committer | Baitinq <[email protected]> | 2025-05-27 20:38:24 +0200 |
| commit | 342d5d74be0d839574d05b852a13d2145d9335e3 (patch) | |
| tree | 90dfe9e96d88cc6ef03061080bfde3783bb77d41 /src | |
| parent | Feature: Start adding structs support (diff) | |
| download | interpreter-342d5d74be0d839574d05b852a13d2145d9335e3.tar.gz interpreter-342d5d74be0d839574d05b852a13d2145d9335e3.tar.bz2 interpreter-342d5d74be0d839574d05b852a13d2145d9335e3.zip | |
Feature: Finish adding struct support :^)
Diffstat (limited to 'src')
| -rw-r--r-- | src/codegen.zig | 159 | ||||
| -rw-r--r-- | src/parser.zig | 34 |
2 files changed, 128 insertions, 65 deletions
diff --git a/src/codegen.zig b/src/codegen.zig index 4f69218..b72e9c4 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -141,68 +141,82 @@ pub const CodeGen = struct { std.debug.assert(statement.* == parser.Node.ASSIGNMENT_STATEMENT); const assignment_statement = statement.ASSIGNMENT_STATEMENT; - if (assignment_statement.lhs.* == .PRIMARY_EXPRESSION) { - const identifier = assignment_statement.lhs.PRIMARY_EXPRESSION.IDENTIFIER; - const variable = try self.generate_expression_value(assignment_statement.rhs, identifier.name); + switch (assignment_statement.lhs.*) { + .PRIMARY_EXPRESSION => { + const identifier = assignment_statement.lhs.PRIMARY_EXPRESSION.IDENTIFIER; + const variable = try self.generate_expression_value(assignment_statement.rhs, identifier.name); + + if (self.environment.scope_stack.items.len == 1) { + try self.environment.add_variable(identifier.name, try self.create_variable(.{ + .value = variable.value, + .type = null, + .node = variable.node, + .node_type = variable.node_type, + .stack_level = null, + })); + return; + } - if (self.environment.scope_stack.items.len == 1) { - try self.environment.add_variable(identifier.name, try self.create_variable(.{ - .value = variable.value, - .type = null, - .node = variable.node, - .node_type = variable.node_type, - .stack_level = null, - })); - return; - } + var ptr: llvm.LLVMValueRef = undefined; + var typ = variable.node_type; + if (assignment_statement.is_declaration) { + var x = try self.get_llvm_type(variable.node_type); + if (variable.node_type.TYPE == .FUNCTION_TYPE) { + x = llvm.LLVMPointerType(x, 0); + } + ptr = llvm.LLVMBuildAlloca(self.builder, x, try std.fmt.allocPrintZ(self.arena, "{s}", .{identifier.name})); + } else { + ptr = self.environment.get_variable(identifier.name).?.value; + typ = self.environment.get_variable(identifier.name).?.node_type; + // TODO: Do this in more places! (everywhere get_llvm_type or get_variable?) Also check types in return and cmp + std.debug.print("TYP {s}: {any} vs {any} -- {any}\n", .{ identifier.name, typ.TYPE, variable.node_type.TYPE, variable.node }); + std.debug.assert(self.compare_types(typ, variable.node_type, assignment_statement.is_dereference)); + } - var ptr: llvm.LLVMValueRef = undefined; - var typ = variable.node_type; - if (assignment_statement.is_declaration) { - var x = try self.get_llvm_type(variable.node_type); - if (variable.node_type.TYPE == .FUNCTION_TYPE) { - x = llvm.LLVMPointerType(x, 0); + if (assignment_statement.is_dereference) { + ptr = llvm.LLVMBuildLoad2(self.builder, try self.get_llvm_type(typ), ptr, ""); } - ptr = llvm.LLVMBuildAlloca(self.builder, x, try std.fmt.allocPrintZ(self.arena, "{s}", .{identifier.name})); - } else { - ptr = self.environment.get_variable(identifier.name).?.value; - typ = self.environment.get_variable(identifier.name).?.node_type; - // TODO: Do this in more places! (everywhere get_llvm_type or get_variable?) Also check types in return and cmp - std.debug.print("TYP {s}: {any} vs {any} -- {any}\n", .{ identifier.name, typ.TYPE, variable.node_type.TYPE, variable.node }); - std.debug.assert(self.compare_types(typ, variable.node_type, assignment_statement.is_dereference)); - } - if (assignment_statement.is_dereference) { - ptr = llvm.LLVMBuildLoad2(self.builder, try self.get_llvm_type(typ), ptr, ""); - } + // NOTE: structs have a null variable.value + if (variable.value != null) { + _ = llvm.LLVMBuildStore(self.builder, variable.value, ptr); + } - // NOTE: structs have a null variable.value - if (variable.value != null) { - _ = llvm.LLVMBuildStore(self.builder, variable.value, ptr); - } + if (assignment_statement.is_dereference) { + ptr = self.environment.get_variable(identifier.name).?.value; + } - if (assignment_statement.is_dereference) { - ptr = self.environment.get_variable(identifier.name).?.value; - } + const new_variable = try self.create_variable(.{ + .value = ptr, + .type = null, + .node = variable.node, + .node_type = typ, + .stack_level = null, + }); + // Adding variable doesnt actually replace the variable of previous scope + if (assignment_statement.is_declaration) { + try self.environment.add_variable(identifier.name, new_variable); + } else { + try self.environment.set_variable(identifier.name, new_variable); + } + }, + .UNARY_EXPRESSION => { + const xd = assignment_statement.lhs.UNARY_EXPRESSION.expression; + const a = try self.generate_expression_value(xd, null); + const variable = try self.generate_expression_value(assignment_statement.rhs, null); + _ = llvm.LLVMBuildStore(self.builder, variable.value, a.value); + }, + .FIELD_ACCESS => |field_access| { + const xd = assignment_statement.lhs.FIELD_ACCESS.expression; + const name = field_access.name; + const ptr = self.environment.get_variable(xd.PRIMARY_EXPRESSION.IDENTIFIER.name).?; - const new_variable = try self.create_variable(.{ - .value = ptr, - .type = null, - .node = variable.node, - .node_type = typ, - .stack_level = null, - }); - // Adding variable doesnt actually replace the variable of previous scope - if (assignment_statement.is_declaration) { - try self.environment.add_variable(identifier.name, new_variable); - } else { - try self.environment.set_variable(identifier.name, new_variable); - } - } else { - const xd = assignment_statement.lhs.UNARY_EXPRESSION.expression; - const a = try self.generate_expression_value(xd, null); - const variable = try self.generate_expression_value(assignment_statement.rhs, null); - _ = llvm.LLVMBuildStore(self.builder, variable.value, a.value); + const x = try self.get_struct_field(ptr, name); + + const variable = try self.generate_expression_value(assignment_statement.rhs, null); + _ = llvm.LLVMBuildStore(self.builder, variable.value, x.value); + }, + else => unreachable, } } @@ -739,6 +753,20 @@ pub const CodeGen = struct { .node_type = exp.typ, }); }, + .FIELD_ACCESS => |exp| { + const ptr = self.environment.get_variable(exp.expression.PRIMARY_EXPRESSION.IDENTIFIER.name).?; + + const x = try self.get_struct_field(ptr, exp.name); + const loaded = llvm.LLVMBuildLoad2(self.builder, try self.get_llvm_type(x.type), x.value, ""); + + return try self.create_variable(.{ + .value = loaded, + .type = null, + .stack_level = null, + .node = expression, + .node_type = x.type, + }); + }, else => unreachable, }; } @@ -765,6 +793,27 @@ pub const CodeGen = struct { }); } + fn get_struct_field(self: *CodeGen, ptr: *Variable, name: []const u8) !struct { value: llvm.LLVMValueRef, type: *parser.Node } { + var fieldIndex: ?usize = null; + for (0.., ptr.node_type.TYPE.STRUCT_TYPE.fields) |i, field| { + std.debug.print("STRUCT: {s}\n", .{name}); + if (std.mem.eql(u8, name, field.PRIMARY_EXPRESSION.IDENTIFIER.name)) { + fieldIndex = i; + break; + } + } + if (fieldIndex == null) unreachable; + + const zero = llvm.LLVMConstInt(llvm.LLVMInt32Type(), 0, 0); + const llvmFieldIndex = llvm.LLVMConstInt(llvm.LLVMInt32Type(), fieldIndex.?, 0); + const indices = @constCast(&[_]llvm.LLVMValueRef{ zero, llvmFieldIndex }); + + return .{ + .value = llvm.LLVMBuildGEP2(self.builder, try self.get_llvm_type(ptr.node_type), ptr.value, indices, indices.len, try std.fmt.allocPrintZ(self.arena, "{s}", .{name})), + .type = ptr.node_type.TYPE.STRUCT_TYPE.fields[fieldIndex.?].PRIMARY_EXPRESSION.IDENTIFIER.type.?, + }; + } + fn get_llvm_type(self: *CodeGen, node: *parser.Node) !llvm.LLVMTypeRef { std.debug.assert(node.* == parser.Node.TYPE); const type_node = node.TYPE; diff --git a/src/parser.zig b/src/parser.zig index f92f0c5..95b4bf2 100644 --- a/src/parser.zig +++ b/src/parser.zig @@ -54,6 +54,10 @@ pub const Node = union(enum) { }, expression: *Node, }, + POSTFIX_EXPRESSION: struct { + lhs: *Node, + rhs: ?*Node, + }, PRIMARY_EXPRESSION: union(enum) { NUMBER: struct { value: i64, @@ -545,7 +549,7 @@ pub const Parser = struct { return lhs; } - // UnaryExpression ::= ("!" | "-" | "*") UnaryExpression | PrimaryExpression + // UnaryExpression ::= ("!" | "-" | "*") UnaryExpression | PostfixExpression fn parse_unary_expression(self: *Parser) ParserError!*Node { errdefer if (!self.try_context) std.debug.print("Error parsing unary expression {any}\n", .{self.peek_token()}); @@ -554,7 +558,7 @@ pub const Parser = struct { const star = self.accept_token(tokenizer.TokenType.MUL) != null; if (!not and !minus and !star) { - return try self.parse_primary_expression(); + return try self.parse_postfix_expression(); } return self.create_node(.{ .UNARY_EXPRESSION = .{ @@ -563,12 +567,25 @@ pub const Parser = struct { } }); } - // PrimaryExpression ::= NULL | NUMBER | BOOLEAN | CHAR | STRING | IDENTIFIER | CastStatement | FunctionCallStatement | FunctionDefinition | StructDefinition | StructInstantiation | FieldAccess | LPAREN Expression RPAREN + // PostfixExpression ::= PrimaryExpression (FunctionCallStatement | FieldAccess )* + fn parse_postfix_expression(self: *Parser) ParserError!*Node { + errdefer if (!self.try_context) std.debug.print("Error parsing postfix expression {any}\n", .{self.peek_token()}); + + if (self.accept_parse(parse_cast_statement)) |stmt| { + return stmt; + } else if (self.accept_parse(parse_function_call_statement)) |stmt| { + return stmt; + } else if (self.accept_parse(parse_field_access)) |stmt| { + return stmt; + } else { + return try self.parse_primary_expression(); + } + } + + // PrimaryExpression ::= NULL | NUMBER | BOOLEAN | CHAR | STRING | IDENTIFIER | FunctionDefinition | StructDefinition | StructInstantiation | FieldAccess | LPAREN Expression RPAREN fn parse_primary_expression(self: *Parser) ParserError!*Node { errdefer if (!self.try_context) std.debug.print("Error parsing primary expression {any}\n", .{self.peek_token()}); - if (self.accept_parse(parse_cast_statement)) |stmt| return stmt; - if (self.accept_parse(parse_function_call_statement)) |stmt| return stmt; if (self.accept_parse(parse_function_definition)) |stmt| return stmt; if (self.accept_parse(parse_struct_definition)) |stmt| return stmt; if (self.accept_parse(parse_struct_instanciation)) |stmt| return stmt; @@ -583,7 +600,6 @@ pub const Parser = struct { const token = self.consume_token() orelse return ParserError.ParsingError; return switch (token.type) { - .DOT => try self.parse_field_access(), .NULL => try self.create_node(.{ .PRIMARY_EXPRESSION = .{ .NULL = void{} }, }), @@ -739,14 +755,12 @@ pub const Parser = struct { }); } - // FieldAccess ::= Expression DOT IDENTIFIER + // FieldAccess ::= PrimaryExpression DOT IDENTIFIER fn parse_field_access(self: *Parser) ParserError!*Node { errdefer if (!self.try_context) std.debug.print("Error parsing field access {any}\n", .{self.peek_token()}); - const expression = try self.parse_expression(); - + const expression = try self.parse_primary_expression(); _ = try self.parse_token(tokenizer.TokenType.DOT); - const ident = try self.parse_token(tokenizer.TokenType.IDENTIFIER); return self.create_node(.{ |