about summary refs log tree commit diff
diff options
context:
space:
mode:
authorBaitinq <[email protected]>2025-06-26 00:08:01 +0200
committerBaitinq <[email protected]>2025-06-26 00:13:12 +0200
commit9bbce9bdced3398b22665d0d65ca0059494c0cc7 (patch)
treecd76099ce2b86daba801361ade868d427f102731
parentboostrap: implement enough for first example to work (diff)
downloadpry-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.pry2
-rw-r--r--src/bootstrap/codegen.pry114
-rw-r--r--src/bootstrap/llvm.pry3
-rw-r--r--src/bootstrap/parser.pry127
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");