about summary refs log tree commit diff
diff options
context:
space:
mode:
authorBaitinq <[email protected]>2025-05-28 00:11:06 +0200
committerBaitinq <[email protected]>2025-05-28 00:11:06 +0200
commit48958afe4e187ce496d3445ee622ec3bc7bc8453 (patch)
treebf6c0ead8240a27e150e9e81dd9207cee4dbe211
parentFeature: Finish adding struct support :^) (diff)
downloadpry-lang-48958afe4e187ce496d3445ee622ec3bc7bc8453.tar.gz
pry-lang-48958afe4e187ce496d3445ee622ec3bc7bc8453.tar.bz2
pry-lang-48958afe4e187ce496d3445ee622ec3bc7bc8453.zip
Feature: Add sizeof builtin function
-rw-r--r--examples/19.src2
-rw-r--r--grammar.ebnf6
-rw-r--r--src/codegen.zig23
-rw-r--r--src/parser.zig35
4 files changed, 60 insertions, 6 deletions
diff --git a/examples/19.src b/examples/19.src
index 5a3543f..2ae1973 100644
--- a/examples/19.src
+++ b/examples/19.src
@@ -3,7 +3,7 @@ extern malloc = (i64) => *void;
 extern free = (*void) => void;
 
 let main = () => i64 {
-	let buf = cast(*i8, malloc(13));
+	let buf = cast(*i8, malloc(sizeof(i8) * 13));
 	(*(buf+cast(*i8, 0))) = 'h';
 	(*(buf+cast(*i8, 1))) = 'e';
 	(*(buf+cast(*i8, 2))) = 'l';
diff --git a/grammar.ebnf b/grammar.ebnf
index 78101f1..cecc65e 100644
--- a/grammar.ebnf
+++ b/grammar.ebnf
@@ -1,6 +1,6 @@
 Program      ::= Statement+
 
-Statement    ::= (AssignmentStatement | ImportDeclaration | ExternDeclaration | CastStatement| FunctionCallStatement | IfStatement | WhileStatement | ReturnStatement | "break" | "continue") SEMICOLON
+Statement    ::= (AssignmentStatement | ImportDeclaration | ExternDeclaration | CastStatement | SizeOfStatement | FunctionCallStatement | IfStatement | WhileStatement | ReturnStatement | "break" | "continue") SEMICOLON
 
 AssignmentStatement ::= ("let")? ("*")? Expression EQUALS Expression
 
@@ -21,6 +21,8 @@ FunctionArguments ::= Expression ("," Expression)*
 Expression ::= EqualityExpression | AdditiveExpression
 
 CastStatement ::= "cast" LPAREN TYPE "," Expression RPAREN
+    
+SizeOfStatement ::= "sizeof" LPAREN TYPE RPAREN
 
 EqualityExpression ::= AdditiveExpression ("==" | "!=" | "<=" | ">=" | "<" | ">") AdditiveExpression
 
@@ -30,7 +32,7 @@ MultiplicativeExpression ::= UnaryExpression (("*" | "/" | "%") UnaryExpression)
 
 UnaryExpression ::= ("!" | "-" | "*") UnaryExpression | PostfixExpression
 
-PostfixExpression ::= PrimaryExpression (FieldAccess | FunctionCallStatement | CastStatement)*
+PostfixExpression ::= PrimaryExpression (FieldAccess | FunctionCallStatement | CastStatement | SizeOfStatement)*
 
 PrimaryExpression ::= NULL | NUMBER | BOOLEAN | CHAR | STRING | IDENTIFIER | FunctionDefinition | StructDefinition | StructInstantiation | FieldAccess | LPAREN Expression RPAREN
 
diff --git a/src/codegen.zig b/src/codegen.zig
index b72e9c4..d246853 100644
--- a/src/codegen.zig
+++ b/src/codegen.zig
@@ -17,6 +17,7 @@ pub const CodeGenError = error{
 
 pub const CodeGen = struct {
     llvm_module: llvm.LLVMModuleRef,
+    llvm_target_data: llvm.LLVMTargetDataRef,
     llvm_context: llvm.LLVMContextRef,
     builder: llvm.LLVMBuilderRef,
     environment: *Environment,
@@ -43,6 +44,7 @@ pub const CodeGen = struct {
         const self = try arena.create(CodeGen);
         self.* = .{
             .llvm_module = module,
+            .llvm_target_data = llvm.LLVMGetModuleDataLayout(module),
             .llvm_context = context,
             .builder = builder,
             .environment = try Environment.init(arena),
@@ -753,6 +755,27 @@ pub const CodeGen = struct {
                     .node_type = exp.typ,
                 });
             },
+            .SIZEOF_STATEMENT => |exp| {
+                const typ = try self.get_llvm_type(exp.typ);
+                const size_in_bits = llvm.LLVMSizeOfTypeInBits(self.llvm_target_data, typ);
+                const size_in_bytes = size_in_bits / 8;
+
+                const size_val = llvm.LLVMConstInt(llvm.LLVMInt64Type(), size_in_bytes, 0);
+
+                return try self.create_variable(.{
+                    .value = size_val,
+                    .type = null,
+                    .node_type = try self.create_node(.{
+                        .TYPE = .{
+                            .SIMPLE_TYPE = .{
+                                .name = "i64",
+                            },
+                        },
+                    }),
+                    .stack_level = null,
+                    .node = expression,
+                });
+            },
             .FIELD_ACCESS => |exp| {
                 const ptr = self.environment.get_variable(exp.expression.PRIMARY_EXPRESSION.IDENTIFIER.name).?;
 
diff --git a/src/parser.zig b/src/parser.zig
index 95b4bf2..5db8fa8 100644
--- a/src/parser.zig
+++ b/src/parser.zig
@@ -111,6 +111,9 @@ pub const Node = union(enum) {
         typ: *Node,
         expression: *Node,
     },
+    SIZEOF_STATEMENT: struct {
+        typ: *Node,
+    },
     BREAK_STATEMENT: void,
     CONTINUE_STATEMENT: void,
 };
@@ -168,12 +171,13 @@ pub const Parser = struct {
         } });
     }
 
-    // Statement    ::= (AssignmentStatement | ImportDeclaration | ExternDeclaration | CastStatement | FunctionCallStatement | IfStatement | WhileStatement | ReturnStatement | "break" | "continue") SEMICOLON
+    // Statement    ::= (AssignmentStatement | ImportDeclaration | ExternDeclaration | CastStatement | SizeOfStatement | FunctionCallStatement | IfStatement | WhileStatement | ReturnStatement | "break" | "continue") SEMICOLON
     fn parse_statement(self: *Parser) ParserError!*Node {
         errdefer if (!self.try_context) std.debug.print("Error parsing statement {any}\n", .{self.peek_token()});
 
         const statement =
-            self.accept_parse(parse_cast_statement) orelse
+            self.accept_parse(parse_cast_statement) orelse //TODO: Can we not deal with cast / sizeof in parser?
+            self.accept_parse(parse_sizeof_statement) orelse
             self.accept_parse(parse_function_call_statement) orelse
             self.accept_parse(parse_if_statement) orelse
             self.accept_parse(parse_while_statement) orelse
@@ -567,12 +571,14 @@ pub const Parser = struct {
         } });
     }
 
-    // PostfixExpression ::= PrimaryExpression (FunctionCallStatement | FieldAccess )*
+    // PostfixExpression ::= PrimaryExpression (CastStatement | SizeOfStatement | 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_sizeof_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| {
@@ -814,6 +820,29 @@ pub const Parser = struct {
         });
     }
 
+    // SizeOfStatement ::= "sizeof" LPAREN TYPE RPAREN
+    fn parse_sizeof_statement(self: *Parser) ParserError!*Node {
+        errdefer if (!self.try_context) std.debug.print("Error parsing sizeof statement {any}\n", .{self.peek_token()});
+
+        const ident = try self.parse_token(tokenizer.TokenType.IDENTIFIER);
+
+        if (!std.mem.eql(u8, "sizeof", ident.type.IDENTIFIER)) {
+            return ParserError.ParsingError;
+        }
+
+        _ = try self.parse_token(tokenizer.TokenType.LPAREN);
+
+        const typ = try self.parse_type();
+
+        _ = try self.parse_token(tokenizer.TokenType.RPAREN);
+
+        return self.create_node(.{
+            .SIZEOF_STATEMENT = .{
+                .typ = typ,
+            },
+        });
+    }
+
     // Type ::= IDENTIFIER | FunctionType
     fn parse_type(self: *Parser) ParserError!*Node {
         errdefer if (!self.try_context) std.debug.print("Error parsing type annotation {any}\n", .{self.peek_token()});