From f669cdf21a09c630a748ace4b067699b6eb6c661 Mon Sep 17 00:00:00 2001 From: Baitinq Date: Mon, 23 Jun 2025 23:20:12 +0200 Subject: boostrap: implement enough for first example to work --- src/bootstrap/codegen.pry | 204 ++++++++++++++++++++++++++++++++++++++++++---- src/bootstrap/llvm.pry | 13 +++ src/bootstrap/parser.pry | 30 +++++-- src/codegen.zig | 11 --- 4 files changed, 224 insertions(+), 34 deletions(-) (limited to 'src') diff --git a/src/bootstrap/codegen.pry b/src/bootstrap/codegen.pry index 7293c09..7d83a3b 100644 --- a/src/bootstrap/codegen.pry +++ b/src/bootstrap/codegen.pry @@ -1,10 +1,60 @@ +import "!hashmap.pry"; + import "llvm.pry"; +let Variable = struct { + value: LLVMValueRef, + type: LLVMTypeRef, + node: *Node, + node_type: *Node, + stack_level: *i64, +}; + +let Scope = struct { + variables: *HashMap, +}; + +let Environment = struct { + scope_stack: **Scope, + scope_stack_len: i64, + arena: *arena, +}; + +let environment_create_scope = (e: *Environment) => void { + let scope = cast(*Scope, arena_alloc((*e).arena, sizeof(Scope))); + (*scope).variables = hashmap_init(16, (*e).arena); + (*((*e).scope_stack + cast(**Scope, (*e).scope_stack_len))) = scope; + (*e).scope_stack_len = (*e).scope_stack_len + 1; + + return; +}; + +let environment_drop_scope = (e: *Environment) => void { + (*e).scope_stack_len = (*e).scope_stack_len - 1; + + return; +}; + +let environment_init = (alloc: *arena) => *Environment { + let e = cast(*Environment, arena_alloc(alloc, sizeof(Environment))); + (*e).scope_stack = cast(**Scope, arena_alloc(alloc, sizeof(*Scope) * 20)); + (*e).scope_stack_len = 0; + (*e).arena = alloc; + + environment_create_scope(e); + + return e; +}; + let codegen = struct { llvm_module: LLVMModuleRef, llvm_context: LLVMContextRef, builder: LLVMBuilderRef, arena: *arena, + environment: *Environment, + + current_function: LLVMValueRef, + current_function_retur_type: *Node, }; let codegen_init = (alloc: *arena) => *codegen { @@ -24,6 +74,7 @@ let codegen_init = (alloc: *arena) => *codegen { (*c).llvm_context = context; (*c).builder = builder; (*c).arena = alloc; + (*c).environment = environment_init(alloc); return c; }; @@ -34,20 +85,33 @@ let create_node = (c: *codegen, n: Node) => *Node { return res; }; -let Variable = struct { - value: LLVMValueRef, - type: LLVMTypeRef, - node: *Node, - node_type: *Node, - stack_level: *i64, -}; - let codegen_create_variable = (c: *codegen, variable: Variable) => *Variable { let v = cast(*Variable, arena_alloc((*c).arena, sizeof(Variable))); *v = variable; return v; }; +let codegen_get_llvm_type = (c: *codegen, node: *Node) => *LLVMTypeRef { + printf("LLVM TYPE: %d\n", (*node).type); + assert((*node).type >= NODE_TYPE_SIMPLE_TYPE); + assert((*node).type <= NODE_TYPE_STRUCT_TYPE); + + assert((*node).type == NODE_TYPE_SIMPLE_TYPE); /* TODO */ + + let simple_type = *cast(*NODE_TYPE_SIMPLE_TYPE_DATA, (*node).data); + + if strcmp(simple_type.name, "i64") { + let r = cast(*LLVMTypeRef, arena_alloc((*c).arena, sizeof(LLVMTypeRef))); + *r = LLVMInt64Type(); + return r; + }; + + printf("NO TYPE!\n"); + assert(false); + + return cast(*LLVMTypeRef, null); +}; + let codegen_generate_literal = (c: *codegen, literal_val: LLVMValueRef, name: *i8, node: *Node, node_type: *Node) => *Variable { /* TODO: Global */ let v = Variable{}; @@ -59,6 +123,8 @@ let codegen_generate_literal = (c: *codegen, literal_val: LLVMValueRef, name: *i return codegen_create_variable(c, v); }; +extern codegen_generate_statement = (*codegen, *Node) => i64; + let codegen_generate_expression_value = (c: *codegen, expression: *Node, name: *i8) => *Variable { if ((*expression).type == NODE_PRIMARY_EXPRESSION_NUMBER) { let n = (*cast(*NODE_PRIMARY_EXPRESSION_NUMBER_DATA, (*expression).data)).value; @@ -77,11 +143,89 @@ let codegen_generate_expression_value = (c: *codegen, expression: *Node, name: * }; if ((*expression).type == NODE_FUNCTION_DEFINITION) { + /* TODO: IMPLEMENT */ printf("ASS %d\n", (*expression).type); - assert(false); /* TODO */ - printf("ERT\n"); + + let builder_pos = LLVMGetInsertBlock((*c).builder); + + let llvm_param_types = cast(*LLVMTypeRef, arena_alloc((*c).arena, sizeof(LLVMTypeRef) * 20)); + let param_types = cast(**Node, arena_alloc((*c).arena, sizeof(*Node) * 20)); + /* TODO: VARARGS */ + + + let function_definition = *cast(*NODE_FUNCTION_DEFINITION_DATA, (*expression).data); + + let i = 0; + /* TODO */ + while i < function_definition.parameters_len { + i = i + 1; + }; + + let retur_type = codegen_get_llvm_type(c, function_definition.retur_type); + if retur_type == cast(*LLVMTypeRef, null) { + printf("LEL\n"); + return cast(*Variable, null); + }; + + let function_type = LLVMFunctionType(*retur_type, llvm_param_types, i, 0); + let function = LLVMAddFunction((*c).llvm_module, name, function_type); + let function_entry = LLVMAppendBasicBlock(function, "entrypoint"); + LLVMPositionBuilderAtEnd((*c).builder, function_entry); + + /* TODO: SCOPE */ + environment_create_scope((*c).environment); + let last_function = (*c).current_function; + (*c).current_function = function; + let last_function_retur_type = (*c).current_function_retur_type; + (*c).current_function_retur_type = function_definition.retur_type; + + /* TODO: Defer */ + + let d = cast(*NODE_TYPE_FUNCTION_TYPE_DATA, arena_alloc((*c).arena, sizeof(NODE_TYPE_FUNCTION_TYPE_DATA))); + (*d).parameters = param_types; + (*d).parameters_len = i; + (*d).retur_type = function_definition.retur_type; + let n = Node{}; + let node_type = create_node(c, n); + (*node_type).type = NODE_TYPE_FUNCTION_TYPE; + (*node_type).data = cast(*void, d); + + /* TODO: Recurisve functions */ + + let params = cast(*LLVMValueRef, arena_alloc((*c).arena, sizeof(LLVMValueRef) * function_definition.parameters_len)); + LLVMGetParams(function, params); + + + /* TODO */ + let parameters_index = 0; + while parameters_index < function_definition.parameters_len { + parameters_index = parameters_index + 1; + }; + + i = 0; + while i < function_definition.statements_len { + let stmt = *(function_definition.statements + cast(**Node, i)); + + let res = codegen_generate_statement(c, stmt); + if res != 0 { + return cast(*Variable, null); + }; + + i = i + 1; + }; + + LLVMPositionBuilderAtEnd((*c).builder, builder_pos); + + let v = Variable{}; + v.value = function; + v.type = cast(LLVMTypeRef, null); + v.stack_level = cast(*i64, null); + v.node = expression; + v.node_type = node_type; + return codegen_create_variable(c, v); }; + printf("ASSERT 1\n"); assert(false); return cast(*Variable, null); @@ -99,19 +243,49 @@ let codegen_generate_assignment_statement = (c: *codegen, stmt: *NODE_ASSIGNMENT return 0; }; + printf("ASSERT 2 %d\n", lhs.type); assert(false); return 0; }; +let codegen_generate_return_statement = (c: *codegen, stmt: *NODE_RETURN_STATEMENT_DATA) => i64 { + printf("HELLO!\n"); + let expression = (*stmt).expression; + + if expression == cast(*Node, null) { + printf("RETURN VOID!\n"); + LLVMBuildRetVoid((*c).builder); + return 0; + }; + + let val = codegen_generate_expression_value(c, expression, cast(*i8, null)); + if val == cast(*Variable, null) { + return 1; + }; + + /* TODO: Check type */ + + LLVMBuildRet((*c).builder, (*val).value); + + printf("BYE!\n"); + + return 0; +}; + let codegen_generate_statement = (c: *codegen, statement: *Node) => i64 { let stmt = *statement; - assert(stmt.type == NODE_ASSIGNMENT_STATEMENT); /* TODO: generate other node types */ - let res = codegen_generate_assignment_statement(c, cast(*NODE_ASSIGNMENT_STATEMENT_DATA, stmt.data)); - if res != 0 { - return 1; + if stmt.type == NODE_ASSIGNMENT_STATEMENT { + return codegen_generate_assignment_statement(c, cast(*NODE_ASSIGNMENT_STATEMENT_DATA, stmt.data)); }; - printf("STMT: %d\n", stmt.type); + + if stmt.type == NODE_RETURN_STATEMENT { + return codegen_generate_return_statement(c, cast(*NODE_RETURN_STATEMENT_DATA, stmt.data)); + }; + + printf("ASSERT 3 %d\n", stmt.type); + assert(false); + return 0; }; diff --git a/src/bootstrap/llvm.pry b/src/bootstrap/llvm.pry index 8cd600f..f958286 100644 --- a/src/bootstrap/llvm.pry +++ b/src/bootstrap/llvm.pry @@ -258,6 +258,7 @@ let LLVMTargetRef = newtype *void; let LLVMValueRef = newtype *void; let LLVMTypeRef = newtype *void; +let LLVMBasicBlockRef = newtype *void; extern LLVMConstInt = (LLVMTypeRef, i64, i64) => LLVMValueRef; extern LLVMInt64Type = () => LLVMTypeRef; @@ -269,6 +270,8 @@ extern LLVMDisposeModule = (LLVMModuleRef) => void; extern LLVMShutdown = () => void; extern LLVMDisposeBuilder = (LLVMBuilderRef) => void; +extern LLVMGetInsertBlock = (LLVMBuilderRef) => LLVMBasicBlockRef; + extern LLVMDumpModule = (LLVMModuleRef) => void; extern LLVMGetDefaultTargetTriple = () => *i8; extern LLVMGetTargetFromTriple = (*i8, *LLVMTargetRef, **i8) => i64; @@ -287,3 +290,13 @@ let LLVMAbortProcessAction = 0; extern LLVMTargetMachineEmitToFile = (LLVMTargetMachineRef, LLVMModuleRef, *i8, i64, **i8) => i64; let LLVMObjectFile = 1; + +extern LLVMFunctionType = (LLVMTypeRef, *LLVMTypeRef, i64, i64) => LLVMTypeRef; +extern LLVMAddFunction = (LLVMModuleRef, *i8, LLVMTypeRef) => LLVMValueRef; +extern LLVMAppendBasicBlock = (LLVMValueRef, *i8) => LLVMBasicBlockRef; +extern LLVMPositionBuilderAtEnd = (LLVMBuilderRef, LLVMBasicBlockRef) => void; + +extern LLVMGetParams = (LLVMValueRef, *LLVMValueRef) => void; + +extern LLVMBuildRetVoid = (LLVMBuilderRef) => void; +extern LLVMBuildRet = (LLVMBuilderRef, LLVMValueRef) => void; diff --git a/src/bootstrap/parser.pry b/src/bootstrap/parser.pry index daac296..0b6d5b6 100644 --- a/src/bootstrap/parser.pry +++ b/src/bootstrap/parser.pry @@ -160,7 +160,7 @@ let NODE_TYPE_SIMPLE_TYPE_DATA = struct { }; let NODE_TYPE_FUNCTION_TYPE_DATA = struct { - parameters: *Node, + parameters: **Node, parameters_len: i64, retur_type: *Node, }; @@ -294,8 +294,6 @@ let parser_parse_type = (p: *parser) => *Node { /* FunctionParameters ::= IDENTIFIER ":" Type ("," IDENTIFIER ":" Type)* */ let parser_parse_function_parameters = (p: *parser) => *slice { - /* TODO: Params */ - let node_list = cast(**Node, arena_alloc((*p).arena, sizeof(**Node) * 20)); let i = 0; while true { @@ -306,12 +304,28 @@ let parser_parse_function_parameters = (p: *parser) => *slice { if ident == cast(*token, null) { break; }; - /* TODO: Rest */ + if parser_accept_token(p, TOKEN_COLON) == cast(*token, null) { + return cast(*slice, null); + }; + let type_annotation = parser_parse_type(p); + if type_annotation == cast(*Node, null) { + return cast(*slice, null); + }; + + let d = cast(*NODE_PRIMARY_EXPRESSION_IDENTIFIER_DATA, arena_alloc((*p).arena, sizeof(NODE_PRIMARY_EXPRESSION_IDENTIFIER_DATA))); + (*d).name = cast(*i8, ident.data); + (*d).type = type_annotation; + let n = Node{}; + n.type = NODE_PRIMARY_EXPRESSION_IDENTIFIER; + n.data = cast(*void, d); + (*(node_list + cast(**Node, i))) = create_node(p, n); + + i = i + 1; }; let s = cast(*slice, arena_alloc((*p).arena, sizeof(slice))); (*s).data = cast(*void, node_list); - (*s).data_len = 0; + (*s).data_len = i; return s; }; @@ -359,9 +373,9 @@ let parser_parse_function_definition = (p: *parser) => *Node { let d = cast(*NODE_FUNCTION_DEFINITION_DATA, arena_alloc((*p).arena, sizeof(NODE_FUNCTION_DEFINITION_DATA))); (*d).statements = statements; (*d).statements_len = i; - (*d).parameters = cast(**Node, params.data); - (*d).parameters_len = params.data_len; - (*d).retur_type = cast(*Node, null); + (*d).parameters = cast(**Node, (*params).data); + (*d).parameters_len = (*params).data_len; + (*d).retur_type = retur_type; let n = Node{}; n.type = NODE_FUNCTION_DEFINITION; diff --git a/src/codegen.zig b/src/codegen.zig index 019110c..1123db8 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -499,17 +499,6 @@ pub const CodeGen = struct { // TODO: This should be done with a defer when `builder_pos` is declared, but for some reason it doesn't work llvm.LLVMPositionBuilderAtEnd(self.builder, builder_pos); - // Global functions - if (name == null or self.environment.scope_stack.items.len == 2) { - return try self.create_variable(.{ - .value = function, - .type = null, - .stack_level = null, - .node = expression, - .node_type = node_type, - }); - } - return try self.create_variable(.{ .value = function, .type = null, -- cgit 1.4.1