You can now forward declare functions!

This commit is contained in:
apio 2022-08-25 19:15:43 +02:00
parent bae0d82f26
commit b1c7a26cfb
4 changed files with 53 additions and 3 deletions

View File

@ -59,6 +59,8 @@ add_executable(
src/AST/FunctionPrototype.h
src/AST/FunctionNode.cpp
src/AST/FunctionNode.h
src/AST/EmptyFunctionNode.cpp
src/AST/EmptyFunctionNode.h
src/GlobalContext.cpp
src/GlobalContext.h
src/utils.cpp

View File

@ -0,0 +1,27 @@
#include "EmptyFunctionNode.h"
#include "../Error.h"
#include "../utils.h"
EmptyFunctionNode::EmptyFunctionNode(FunctionPrototype prototype) : TopLevelNode(), prototype(prototype)
{
}
void EmptyFunctionNode::codegen(IRBuilder* generator, llvm::Module* module)
{
llvm::Function* Function = module->getFunction(prototype.name);
if (!Function)
{
llvm::FunctionType* Type = prototype.toFunctionType();
Function = llvm::Function::Create(Type, llvm::Function::ExternalLinkage, prototype.name, *module);
}
else
{
if (!equals(Function->getFunctionType(), prototype.toFunctionType()))
{
// FIXME: add location information to AST nodes, to add information to these errors
Error::throw_error_without_location(
format_string("Function %s redefined with different prototype", prototype.name.c_str()));
}
}
}

View File

@ -0,0 +1,16 @@
#pragma once
#include "../IRBuilder.h"
#include "FunctionPrototype.h"
#include "TopLevelNode.h"
class EmptyFunctionNode final : public TopLevelNode
{
private:
FunctionPrototype prototype;
public:
EmptyFunctionNode(FunctionPrototype prototype);
~EmptyFunctionNode() = default;
void codegen(IRBuilder* generator, llvm::Module* module) override;
};

View File

@ -1,4 +1,5 @@
#include "Parser.h"
#include "AST/EmptyFunctionNode.h"
#include "AST/FunctionNode.h"
#include "AST/MulNode.h"
#include "AST/SumNode.h"
@ -97,6 +98,7 @@ Result<TopLevelNode> Parser::toplevel()
Result<TopLevelNode> Parser::function()
{
FunctionPrototype proto;
Token* ftoken = current_token;
proto.returnType = llvm::IntegerType::getInt32Ty(*globalContext); // FIXME: allow specifying return type
proto.arguments = {}; // FIXME: allow specifying arguments
if (current_token->tk_type != TT_Let)
@ -110,9 +112,12 @@ Result<TopLevelNode> Parser::function()
proto.name = current_token->string_value;
advance();
if (current_token->tk_type != TT_In && current_token->tk_type != TT_Semicolon)
return Err<TopLevelNode>("Expected 'in'", current_token);
return Err<TopLevelNode>("Expected 'in' or semicolon", current_token);
if (current_token->tk_type == TT_Semicolon)
return Err<TopLevelNode>("Functions without a body are unsupported (for now)", current_token);
{
advance();
return Ok<TopLevelNode>(new EmptyFunctionNode(proto), ftoken);
}
advance();
if (current_token->tk_type != TT_LBracket)
return Err<TopLevelNode>("Invalid syntax",
@ -123,5 +128,5 @@ Result<TopLevelNode> Parser::function()
if (current_token->tk_type != TT_RBracket)
return Err<TopLevelNode>(format_string("Invalid syntax %d", current_token->tk_type), current_token);
advance();
return Ok<TopLevelNode>(new FunctionNode(proto, body.get()), current_token);
return Ok<TopLevelNode>(new FunctionNode(proto, body.get()), ftoken);
}