You can now forward declare functions!
This commit is contained in:
parent
bae0d82f26
commit
b1c7a26cfb
@ -59,6 +59,8 @@ add_executable(
|
|||||||
src/AST/FunctionPrototype.h
|
src/AST/FunctionPrototype.h
|
||||||
src/AST/FunctionNode.cpp
|
src/AST/FunctionNode.cpp
|
||||||
src/AST/FunctionNode.h
|
src/AST/FunctionNode.h
|
||||||
|
src/AST/EmptyFunctionNode.cpp
|
||||||
|
src/AST/EmptyFunctionNode.h
|
||||||
src/GlobalContext.cpp
|
src/GlobalContext.cpp
|
||||||
src/GlobalContext.h
|
src/GlobalContext.h
|
||||||
src/utils.cpp
|
src/utils.cpp
|
||||||
|
27
src/AST/EmptyFunctionNode.cpp
Normal file
27
src/AST/EmptyFunctionNode.cpp
Normal 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()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
16
src/AST/EmptyFunctionNode.h
Normal file
16
src/AST/EmptyFunctionNode.h
Normal 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;
|
||||||
|
};
|
@ -1,4 +1,5 @@
|
|||||||
#include "Parser.h"
|
#include "Parser.h"
|
||||||
|
#include "AST/EmptyFunctionNode.h"
|
||||||
#include "AST/FunctionNode.h"
|
#include "AST/FunctionNode.h"
|
||||||
#include "AST/MulNode.h"
|
#include "AST/MulNode.h"
|
||||||
#include "AST/SumNode.h"
|
#include "AST/SumNode.h"
|
||||||
@ -97,6 +98,7 @@ Result<TopLevelNode> Parser::toplevel()
|
|||||||
Result<TopLevelNode> Parser::function()
|
Result<TopLevelNode> Parser::function()
|
||||||
{
|
{
|
||||||
FunctionPrototype proto;
|
FunctionPrototype proto;
|
||||||
|
Token* ftoken = current_token;
|
||||||
proto.returnType = llvm::IntegerType::getInt32Ty(*globalContext); // FIXME: allow specifying return type
|
proto.returnType = llvm::IntegerType::getInt32Ty(*globalContext); // FIXME: allow specifying return type
|
||||||
proto.arguments = {}; // FIXME: allow specifying arguments
|
proto.arguments = {}; // FIXME: allow specifying arguments
|
||||||
if (current_token->tk_type != TT_Let)
|
if (current_token->tk_type != TT_Let)
|
||||||
@ -110,9 +112,12 @@ Result<TopLevelNode> Parser::function()
|
|||||||
proto.name = current_token->string_value;
|
proto.name = current_token->string_value;
|
||||||
advance();
|
advance();
|
||||||
if (current_token->tk_type != TT_In && current_token->tk_type != TT_Semicolon)
|
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)
|
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();
|
advance();
|
||||||
if (current_token->tk_type != TT_LBracket)
|
if (current_token->tk_type != TT_LBracket)
|
||||||
return Err<TopLevelNode>("Invalid syntax",
|
return Err<TopLevelNode>("Invalid syntax",
|
||||||
@ -123,5 +128,5 @@ Result<TopLevelNode> Parser::function()
|
|||||||
if (current_token->tk_type != TT_RBracket)
|
if (current_token->tk_type != TT_RBracket)
|
||||||
return Err<TopLevelNode>(format_string("Invalid syntax %d", current_token->tk_type), current_token);
|
return Err<TopLevelNode>(format_string("Invalid syntax %d", current_token->tk_type), current_token);
|
||||||
advance();
|
advance();
|
||||||
return Ok<TopLevelNode>(new FunctionNode(proto, body.get()), current_token);
|
return Ok<TopLevelNode>(new FunctionNode(proto, body.get()), ftoken);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user