diff options
| author | Baitinq <[email protected]> | 2025-06-26 00:08:01 +0200 |
|---|---|---|
| committer | Baitinq <[email protected]> | 2025-06-26 00:13:12 +0200 |
| commit | 9bbce9bdced3398b22665d0d65ca0059494c0cc7 (patch) | |
| tree | cd76099ce2b86daba801361ade868d427f102731 | |
| parent | boostrap: implement enough for first example to work (diff) | |
| download | pry-lang-9bbce9bdced3398b22665d0d65ca0059494c0cc7.tar.gz pry-lang-9bbce9bdced3398b22665d0d65ca0059494c0cc7.tar.bz2 pry-lang-9bbce9bdced3398b22665d0d65ca0059494c0cc7.zip | |
boostrap: implement support for declaring extern functions
| -rw-r--r-- | examples/-1.pry | 2 | ||||
| -rw-r--r-- | src/bootstrap/codegen.pry | 114 | ||||
| -rw-r--r-- | src/bootstrap/llvm.pry | 3 | ||||
| -rw-r--r-- | src/bootstrap/parser.pry | 127 |
4 files changed, 232 insertions, 14 deletions
diff --git a/examples/-1.pry b/examples/-1.pry index 4b77e10..5093a7e 100644 --- a/examples/-1.pry +++ b/examples/-1.pry @@ -1,5 +1,7 @@ /* HELLO! Welcome to the unnamed language */ +extern printf = (*i8, varargs) => void; + let main = () => i64 { return 7; }; diff --git a/src/bootstrap/codegen.pry b/src/bootstrap/codegen.pry index 7d83a3b..3a809fe 100644 --- a/src/bootstrap/codegen.pry +++ b/src/bootstrap/codegen.pry @@ -92,21 +92,93 @@ let codegen_create_variable = (c: *codegen, variable: Variable) => *Variable { }; 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 */ + if (*node).type == NODE_TYPE_SIMPLE_TYPE { + let simple_type = *cast(*NODE_TYPE_SIMPLE_TYPE_DATA, (*node).data); - let simple_type = *cast(*NODE_TYPE_SIMPLE_TYPE_DATA, (*node).data); + if strcmp(simple_type.name, "i8") { + let r = cast(*LLVMTypeRef, arena_alloc((*c).arena, sizeof(LLVMTypeRef))); + *r = LLVMInt8Type(); + return r; + }; + + if strcmp(simple_type.name, "i64") { + let r = cast(*LLVMTypeRef, arena_alloc((*c).arena, sizeof(LLVMTypeRef))); + *r = LLVMInt64Type(); + return r; + }; + + if strcmp(simple_type.name, "void") { + let r = cast(*LLVMTypeRef, arena_alloc((*c).arena, sizeof(LLVMTypeRef))); + *r = LLVMVoidType(); + return r; + }; + + if strcmp(simple_type.name, "varargs") { /* Hack for varargs (only used for printf) */ + let r = cast(*LLVMTypeRef, arena_alloc((*c).arena, sizeof(LLVMTypeRef))); + *r = LLVMPointerType(LLVMInt64Type(), 0); + return r; + }; + + printf("NO SIMPLE TYPE %s!\n", simple_type.name); + assert(false); + }; - if strcmp(simple_type.name, "i64") { + if (*node).type == NODE_TYPE_FUNCTION_TYPE { + let function_type = *cast(*NODE_TYPE_FUNCTION_TYPE_DATA, (*node).data); + let retur_type = codegen_get_llvm_type(c, function_type.retur_type); + if retur_type == cast(*LLVMTypeRef, null) { + return cast(*LLVMTypeRef, null); + }; + let paramtypes = cast(*LLVMTypeRef, arena_alloc((*c).arena, sizeof(LLVMTypeRef) * 20)); + let paramtypes_len = 0; + let is_varargs = 0; + + let i = 0; + while i < function_type.parameters_len { + let param = *(function_type.parameters + cast(**Node, i)); + if (*param).type == NODE_TYPE_SIMPLE_TYPE { + let simple_type = *cast(*NODE_TYPE_SIMPLE_TYPE_DATA, (*param).data); + if strcmp(simple_type.name, "varargs") { + is_varargs = 1; + i = i + 1; + continue; + }; + }; + let typ = codegen_get_llvm_type(c, param); + if typ == cast(*LLVMTypeRef, null) { + return cast(*LLVMTypeRef, null); + }; + if (*param).type == NODE_TYPE_FUNCTION_TYPE { + *typ = LLVMPointerType(*typ, 0); + }; + + (*(paramtypes + cast(*LLVMTypeRef, paramtypes_len))) = *typ; + paramtypes_len = paramtypes_len + 1; + + i = i + 1; + }; + let function_type = LLVMFunctionType(*retur_type, paramtypes, paramtypes_len, is_varargs); let r = cast(*LLVMTypeRef, arena_alloc((*c).arena, sizeof(LLVMTypeRef))); - *r = LLVMInt64Type(); + *r = function_type; + printf("FUNCTION\n"); return r; }; - printf("NO TYPE!\n"); + if (*node).type == NODE_TYPE_POINTER_TYPE { + let pointer_type = *cast(*NODE_TYPE_POINTER_TYPE_DATA, (*node).data); + let inner_type = codegen_get_llvm_type(c, pointer_type.type); + if inner_type == cast(*LLVMTypeRef, null) { + return cast(*LLVMTypeRef, null); + }; + let r = cast(*LLVMTypeRef, arena_alloc((*c).arena, sizeof(LLVMTypeRef))); + *r = LLVMPointerType(*inner_type, 0); + return r; + }; + + printf("NO TYPEEE BOI %d\n", (*node).type); assert(false); return cast(*LLVMTypeRef, null); @@ -126,7 +198,9 @@ let codegen_generate_literal = (c: *codegen, literal_val: LLVMValueRef, name: *i extern codegen_generate_statement = (*codegen, *Node) => i64; let codegen_generate_expression_value = (c: *codegen, expression: *Node, name: *i8) => *Variable { + printf("NAME: %s\n", name); if ((*expression).type == NODE_PRIMARY_EXPRESSION_NUMBER) { + printf("THIS\n"); let n = (*cast(*NODE_PRIMARY_EXPRESSION_NUMBER_DATA, (*expression).data)).value; printf("X: %d\n", n); @@ -143,6 +217,7 @@ let codegen_generate_expression_value = (c: *codegen, expression: *Node, name: * }; if ((*expression).type == NODE_FUNCTION_DEFINITION) { + printf("THIS2\n"); /* TODO: IMPLEMENT */ printf("ASS %d\n", (*expression).type); @@ -163,7 +238,7 @@ let codegen_generate_expression_value = (c: *codegen, expression: *Node, name: * let retur_type = codegen_get_llvm_type(c, function_definition.retur_type); if retur_type == cast(*LLVMTypeRef, null) { - printf("LEL\n"); + printf("LEL2\n"); return cast(*Variable, null); }; @@ -208,6 +283,7 @@ let codegen_generate_expression_value = (c: *codegen, expression: *Node, name: * let res = codegen_generate_statement(c, stmt); if res != 0 { + printf("LEL\n"); return cast(*Variable, null); }; @@ -224,6 +300,30 @@ let codegen_generate_expression_value = (c: *codegen, expression: *Node, name: * v.node_type = node_type; return codegen_create_variable(c, v); }; + + if ((*expression).type == NODE_TYPE_FUNCTION_TYPE) { + let e = *((*c).environment); + printf("LLEL\n"); + assert(e.scope_stack_len == 1); + printf("THIS3\n"); + + /* TODO: Check if already exists */ + + let function_type = codegen_get_llvm_type(c, expression); + if function_type == cast(*LLVMTypeRef, null) { + printf("LOL\n"); + return cast(*Variable, null); + }; + let function = LLVMAddFunction((*c).llvm_module, name, *function_type); + let v = Variable{}; + v.value = function; + v.type = cast(LLVMTypeRef, null); + v.stack_level = cast(*i64, null); + v.node = expression; + v.node_type = expression; + printf("RET\n"); + return codegen_create_variable(c, v); + }; printf("ASSERT 1\n"); assert(false); diff --git a/src/bootstrap/llvm.pry b/src/bootstrap/llvm.pry index f958286..85b3c2b 100644 --- a/src/bootstrap/llvm.pry +++ b/src/bootstrap/llvm.pry @@ -262,6 +262,8 @@ let LLVMBasicBlockRef = newtype *void; extern LLVMConstInt = (LLVMTypeRef, i64, i64) => LLVMValueRef; extern LLVMInt64Type = () => LLVMTypeRef; +extern LLVMInt8Type = () => LLVMTypeRef; +extern LLVMVoidType = () => LLVMTypeRef; extern LLVMModuleCreateWithName = (*i8) => LLVMModuleRef; extern LLVMGetGlobalContext = () => LLVMContextRef; @@ -300,3 +302,4 @@ extern LLVMGetParams = (LLVMValueRef, *LLVMValueRef) => void; extern LLVMBuildRetVoid = (LLVMBuilderRef) => void; extern LLVMBuildRet = (LLVMBuilderRef, LLVMValueRef) => void; +extern LLVMPointerType = (LLVMTypeRef, i64) => LLVMTypeRef; diff --git a/src/bootstrap/parser.pry b/src/bootstrap/parser.pry index 0b6d5b6..ebbb143 100644 --- a/src/bootstrap/parser.pry +++ b/src/bootstrap/parser.pry @@ -274,20 +274,126 @@ let parser_parse_return_statement = (p: *parser) => *Node { return create_node(p, r); }; +extern parser_parse_type = (*parser) => *Node; + +/* FunctionType ::= LPAREN (Type ("," Type)*)? RPAREN ARROW Type */ +let parser_parse_function_type = (p: *parser) => *Node { + if parser_accept_token(p, TOKEN_LPAREN) == cast(*token, null) { + return cast(*Node, null); + }; + + let parameters = cast(**Node, arena_alloc((*p).arena, sizeof(*Node) * 20)); + let parameters_len = 0; + let first = true; + while true { + if !first { + parser_accept_token(p, TOKEN_COMMA); + }; + first = false; + let type_annotation = parser_accept_parse(p, parser_parse_type); + if type_annotation == cast(*Node, null) { + break; + }; + (*(parameters + cast(**Node, parameters_len))) = type_annotation; + parameters_len = parameters_len + 1; + + }; + + if parser_accept_token(p, TOKEN_RPAREN) == cast(*token, null) { + return cast(*Node, null); + }; + if parser_accept_token(p, TOKEN_ARROW) == cast(*token, null) { + return cast(*Node, null); + }; + + let retur_typ = parser_parse_type(p); + if retur_typ == cast(*Node, null) { + return cast(*Node, null); + }; + + let d = cast(*NODE_TYPE_FUNCTION_TYPE_DATA, arena_alloc((*p).arena, sizeof(NODE_TYPE_FUNCTION_TYPE_DATA))); + (*d).parameters = parameters; + (*d).parameters_len = parameters_len; + (*d).retur_type = retur_typ; + + let r = Node{}; + r.type = NODE_TYPE_FUNCTION_TYPE; + r.data = cast(*void, d); + + return create_node(p, r); +}; + /* Type ::= IDENTIFIER | FunctionType */ let parser_parse_type = (p: *parser) => *Node { - /* TODO: Function type */ + let typ = parser_accept_parse(p, parser_parse_function_type); + if typ != cast(*Node, null) { + return typ; + }; + let to = parser_consume_token(p); assert(to != cast(*token, null)); - assert((*to).type == TOKEN_IDENTIFIER); - let d = cast(*NODE_TYPE_SIMPLE_TYPE_DATA, arena_alloc((*p).arena, sizeof(NODE_TYPE_SIMPLE_TYPE_DATA))); - (*d).name = cast(*i8, (*to).data); - (*d).underlying_type = cast(*Node, null); + if (*to).type == TOKEN_IDENTIFIER { + let d = cast(*NODE_TYPE_SIMPLE_TYPE_DATA, arena_alloc((*p).arena, sizeof(NODE_TYPE_SIMPLE_TYPE_DATA))); + (*d).name = cast(*i8, (*to).data); + (*d).underlying_type = cast(*Node, null); + + let r = Node{}; + r.type = NODE_TYPE_SIMPLE_TYPE; + r.data = cast(*void, d); + + return create_node(p, r); + }; + + if (*to).type == TOKEN_MUL { + let d = cast(*NODE_TYPE_POINTER_TYPE_DATA, arena_alloc((*p).arena, sizeof(NODE_TYPE_POINTER_TYPE_DATA))); + (*d).type = parser_parse_type(p); + + let r = Node{}; + r.type = NODE_TYPE_POINTER_TYPE; + r.data = cast(*void, d); + + return create_node(p, r); + }; + + return cast(*Node, null); +}; + +/* ExternDeclaration ::= "extern" IDENTIFIER EQUALS Type */ +let parser_parse_extern_declaration = (p: *parser) => *Node { + if parser_accept_token(p, TOKEN_EXTERN) == cast(*token, null) { + return cast(*Node, null); + }; + + let ident = parser_accept_token(p, TOKEN_IDENTIFIER); + if ident == cast(*token, null) { + return cast(*Node, null); + }; + if parser_accept_token(p, TOKEN_EQUALS) == cast(*token, null) { + return cast(*Node, null); + }; + let typ = parser_parse_type(p); + if typ == cast(*Node, null) { + return cast(*Node, 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 = cast(*Node, null); + + let n = Node{}; + n.type = NODE_PRIMARY_EXPRESSION_IDENTIFIER; + n.data = cast(*void, d); + + let dd = cast(*NODE_ASSIGNMENT_STATEMENT_DATA, arena_alloc((*p).arena, sizeof(NODE_ASSIGNMENT_STATEMENT_DATA))); + (*dd).is_declaration = false; + (*dd).is_dereference = false; + (*dd).lhs = create_node(p, n); + (*dd).rhs = typ; let r = Node{}; - r.type = NODE_TYPE_SIMPLE_TYPE; - r.data = cast(*void, d); + r.type = NODE_ASSIGNMENT_STATEMENT; + r.data = cast(*void, dd); return create_node(p, r); }; @@ -503,6 +609,13 @@ let parser_parse_statement = (p: *parser) => *Node { return retu; }; + let retu = parser_accept_parse(p, parser_parse_extern_declaration); + if retu != cast(*Node, null) { + if parser_accept_token(p, TOKEN_SEMICOLON) == cast(*token, null) { + return cast(*Node, null); + }; + return retu; + }; printf("None\n"); |