Compare commits

...

6 Commits

11 changed files with 120 additions and 29 deletions

View File

@ -119,7 +119,7 @@ namespace types {
[](codegen::Builder& builder, std::shared_ptr<Type> ty, llvm::Value* ptr) { [](codegen::Builder& builder, std::shared_ptr<Type> ty, llvm::Value* ptr) {
codegen::TypeMap structs {}; codegen::TypeMap structs {};
auto llvm_ty = ty->codegen(builder, structs); auto llvm_ty = ty->codegen(builder, structs);
auto loaded = builder.builder->CreateLoad(llvm_ty, ptr); auto loaded = builder.builder->CreateLoad(llvm_ty, ptr, "load");
auto const_1 = llvm::ConstantInt::get(llvm_ty, 1); auto const_1 = llvm::ConstantInt::get(llvm_ty, 1);
auto result = builder.builder->CreateAdd(loaded, const_1, "add"); auto result = builder.builder->CreateAdd(loaded, const_1, "add");
builder.builder->CreateStore(result, ptr); builder.builder->CreateStore(result, ptr);
@ -132,7 +132,7 @@ namespace types {
[](codegen::Builder& builder, std::shared_ptr<Type> ty, llvm::Value* ptr) { [](codegen::Builder& builder, std::shared_ptr<Type> ty, llvm::Value* ptr) {
codegen::TypeMap structs {}; codegen::TypeMap structs {};
auto llvm_ty = ty->codegen(builder, structs); auto llvm_ty = ty->codegen(builder, structs);
auto loaded = builder.builder->CreateLoad(llvm_ty, ptr); auto loaded = builder.builder->CreateLoad(llvm_ty, ptr, "load");
auto const_1 = llvm::ConstantInt::get(llvm_ty, 1); auto const_1 = llvm::ConstantInt::get(llvm_ty, 1);
auto result = builder.builder->CreateAdd(loaded, const_1, "add"); auto result = builder.builder->CreateAdd(loaded, const_1, "add");
builder.builder->CreateStore(result, ptr); builder.builder->CreateStore(result, ptr);
@ -145,7 +145,7 @@ namespace types {
[](codegen::Builder& builder, std::shared_ptr<Type> ty, llvm::Value* ptr) { [](codegen::Builder& builder, std::shared_ptr<Type> ty, llvm::Value* ptr) {
codegen::TypeMap structs {}; codegen::TypeMap structs {};
auto llvm_ty = ty->codegen(builder, structs); auto llvm_ty = ty->codegen(builder, structs);
auto loaded = builder.builder->CreateLoad(llvm_ty, ptr); auto loaded = builder.builder->CreateLoad(llvm_ty, ptr, "load");
auto const_1 = llvm::ConstantInt::get(llvm_ty, 1); auto const_1 = llvm::ConstantInt::get(llvm_ty, 1);
auto result = builder.builder->CreateSub(loaded, const_1, "sub"); auto result = builder.builder->CreateSub(loaded, const_1, "sub");
builder.builder->CreateStore(result, ptr); builder.builder->CreateStore(result, ptr);
@ -158,7 +158,7 @@ namespace types {
[](codegen::Builder& builder, std::shared_ptr<Type> ty, llvm::Value* ptr) { [](codegen::Builder& builder, std::shared_ptr<Type> ty, llvm::Value* ptr) {
codegen::TypeMap structs {}; codegen::TypeMap structs {};
auto llvm_ty = ty->codegen(builder, structs); auto llvm_ty = ty->codegen(builder, structs);
auto loaded = builder.builder->CreateLoad(llvm_ty, ptr); auto loaded = builder.builder->CreateLoad(llvm_ty, ptr, "load");
auto const_1 = llvm::ConstantInt::get(llvm_ty, 1); auto const_1 = llvm::ConstantInt::get(llvm_ty, 1);
auto result = builder.builder->CreateSub(loaded, const_1, "sub"); auto result = builder.builder->CreateSub(loaded, const_1, "sub");
builder.builder->CreateStore(result, ptr); builder.builder->CreateStore(result, ptr);

View File

@ -11,7 +11,16 @@
namespace codegen { namespace codegen {
Scope Scope::with_lvalue() { Scope Scope::with_lvalue() {
return Scope{ this->binops, this->unops, this->casts, this->structs, this->values, true }; return Scope{
.binops = this->binops,
.unops = this->unops,
.casts = this->casts,
.structs = this->structs,
.values = this->values,
.is_lvalue = true,
.continue_bb = this->continue_bb,
.break_bb = this->break_bb,
};
} }
} }
@ -358,7 +367,7 @@ namespace AST {
} }
auto gep = builder.builder->CreateStructGEP( auto gep = builder.builder->CreateStructGEP(
ptr_ty->m_inner->codegen(builder, scope.structs), struct_ptr.value, idx); ptr_ty->m_inner->codegen(builder, scope.structs), struct_ptr.value, idx, "struct_gep");
if (scope.is_lvalue) { if (scope.is_lvalue) {
@ -544,13 +553,15 @@ namespace AST {
builder.block = then_block; builder.block = then_block;
builder.builder->SetInsertPoint(then_block); builder.builder->SetInsertPoint(then_block);
this->m_then->codegen(builder, scope, allocator); this->m_then->codegen(builder, scope, allocator);
builder.builder->CreateBr(after_block); if (builder.block->getTerminator() == nullptr)
builder.builder->CreateBr(after_block);
if (else_block.has_value()) { if (else_block.has_value()) {
builder.block = *else_block; builder.block = *else_block;
builder.builder->SetInsertPoint(*else_block); builder.builder->SetInsertPoint(*else_block);
this->m_else->get()->codegen(builder, scope, allocator); this->m_else->get()->codegen(builder, scope, allocator);
builder.builder->CreateBr(after_block); if (builder.block->getTerminator() == nullptr)
builder.builder->CreateBr(after_block);
} }
builder.block = after_block; builder.block = after_block;
@ -570,14 +581,19 @@ namespace AST {
auto cond_bb = llvm::BasicBlock::Create(*builder.context, "for-cond", function); auto cond_bb = llvm::BasicBlock::Create(*builder.context, "for-cond", function);
auto inner_bb = llvm::BasicBlock::Create(*builder.context, "for-inner", function); auto inner_bb = llvm::BasicBlock::Create(*builder.context, "for-inner", function);
auto after_bb = llvm::BasicBlock::Create(*builder.context, "for-after", function); auto after_bb = llvm::BasicBlock::Create(*builder.context, "for-after", function);
auto done_bb = llvm::BasicBlock::Create(*builder.context, "for-done", function);
builder.builder->CreateBr(cond_bb); builder.builder->CreateBr(cond_bb);
codegen::Scope inner_scope{ scope };
inner_scope.continue_bb = after_bb;
inner_scope.break_bb = done_bb;
// Loop conditional // Loop conditional
builder.builder->SetInsertPoint(cond_bb); builder.builder->SetInsertPoint(cond_bb);
if (this->m_cond) { if (this->m_cond) {
auto cond_res = (*this->m_cond)->codegen(builder, scope, allocator); auto cond_res = (*this->m_cond)->codegen(builder, inner_scope, allocator);
builder.builder->CreateCondBr(cond_res.value, inner_bb, after_bb); builder.builder->CreateCondBr(cond_res.value, inner_bb, done_bb);
} }
else { else {
builder.builder->CreateBr(inner_bb); builder.builder->CreateBr(inner_bb);
@ -586,14 +602,19 @@ namespace AST {
// Loop inner block // Loop inner block
builder.block = inner_bb; builder.block = inner_bb;
builder.builder->SetInsertPoint(inner_bb); builder.builder->SetInsertPoint(inner_bb);
this->m_loop->codegen(builder, scope, allocator); this->m_loop->codegen(builder, inner_scope, allocator);
builder.builder->CreateBr(after_bb);
// Loop after-part
builder.block = after_bb;
builder.builder->SetInsertPoint(after_bb);
if (this->m_after) if (this->m_after)
(*this->m_after)->codegen(builder, scope, allocator); (*this->m_after)->codegen(builder, inner_scope, allocator);
builder.builder->CreateBr(cond_bb); builder.builder->CreateBr(cond_bb);
// Loop after // Loop after
builder.block = after_bb; builder.block = done_bb;
builder.builder->SetInsertPoint(after_bb); builder.builder->SetInsertPoint(done_bb);
} }
void WhileStatement::codegen(codegen::Builder& builder, codegen::Scope& scope, codegen::StackAllocator& allocator) { void WhileStatement::codegen(codegen::Builder& builder, codegen::Scope& scope, codegen::StackAllocator& allocator) {
@ -609,10 +630,14 @@ namespace AST {
builder.builder->CreateBr(cond_bb); builder.builder->CreateBr(cond_bb);
codegen::Scope inner_scope{ scope };
inner_scope.continue_bb = cond_bb;
inner_scope.break_bb = after_bb;
// While condition // While condition
builder.builder->SetInsertPoint(cond_bb); builder.builder->SetInsertPoint(cond_bb);
if (this->m_cond) { if (this->m_cond) {
auto cond_value = (*this->m_cond)->codegen(builder, scope, allocator); auto cond_value = (*this->m_cond)->codegen(builder, inner_scope, allocator);
builder.builder->CreateCondBr(cond_value.value, inner_bb, after_bb); builder.builder->CreateCondBr(cond_value.value, inner_bb, after_bb);
} }
else { else {
@ -622,7 +647,7 @@ namespace AST {
// While loop // While loop
builder.builder->SetInsertPoint(inner_bb); builder.builder->SetInsertPoint(inner_bb);
builder.block = inner_bb; builder.block = inner_bb;
this->m_loop->codegen(builder, scope, allocator); this->m_loop->codegen(builder, inner_scope, allocator);
builder.builder->CreateBr(cond_bb); builder.builder->CreateBr(cond_bb);
// After // After
@ -630,31 +655,35 @@ namespace AST {
builder.block = after_bb; builder.block = after_bb;
} }
void CompoundStatement::codegen(codegen::Builder& builder, codegen::Scope&, codegen::StackAllocator&) { void CompoundStatement::codegen(codegen::Builder& builder, codegen::Scope& scope, codegen::StackAllocator& allocator) {
if (!builder.block) if (!builder.block)
return; return;
builder.builder->SetInsertPoint(builder.block); builder.builder->SetInsertPoint(builder.block);
throw CompileError("TODO", this->m_meta); codegen::Scope inner{ scope };
for (auto& statement : this->m_statements)
statement->codegen(builder, inner, allocator);
} }
void BreakStatement::codegen(codegen::Builder& builder, codegen::Scope&, codegen::StackAllocator&) { void BreakStatement::codegen(codegen::Builder& builder, codegen::Scope& scope, codegen::StackAllocator&) {
if (!builder.block) if (!builder.block)
return; return;
builder.builder->SetInsertPoint(builder.block); builder.builder->SetInsertPoint(builder.block);
if (scope.break_bb == nullptr)
throw CompileError("TODO", this->m_meta); throw CompileError("No break_bb!", this->m_meta);
builder.builder->CreateBr(scope.break_bb);
} }
void ContinueStatement::codegen(codegen::Builder& builder, codegen::Scope&, codegen::StackAllocator&) { void ContinueStatement::codegen(codegen::Builder& builder, codegen::Scope& scope, codegen::StackAllocator&) {
if (!builder.block) if (!builder.block)
return; return;
builder.builder->SetInsertPoint(builder.block); builder.builder->SetInsertPoint(builder.block);
if (scope.continue_bb == nullptr)
throw CompileError("TODO", this->m_meta); throw CompileError("No continue_bb!", this->m_meta);
builder.builder->CreateBr(scope.continue_bb);
} }
void Function::codegen(codegen::Builder& builder, codegen::Scope& scope) { void Function::codegen(codegen::Builder& builder, codegen::Scope& scope) {

View File

@ -28,6 +28,9 @@ namespace codegen {
bool is_lvalue; bool is_lvalue;
llvm::BasicBlock* continue_bb;
llvm::BasicBlock* break_bb;
Scope with_lvalue(); Scope with_lvalue();
}; };
} }

View File

@ -140,6 +140,8 @@ std::optional<CompileOutput> compile(std::string_view in_filename) {
.structs = {}, .structs = {},
.values = {}, .values = {},
.is_lvalue = false, .is_lvalue = false,
.continue_bb = nullptr,
.break_bb = nullptr,
}; };
try { try {

View File

@ -523,6 +523,35 @@ namespace parsing {
token::TokenStream inner{ stream }; token::TokenStream inner{ stream };
auto before_meta = inner.metadata(); auto before_meta = inner.metadata();
try { try {
if (inner.peek().type == token::Type::BreakKeyword) {
inner.next();
stream.m_position = inner.m_position;
auto ret = new AST::BreakStatement{ before_meta + stream.metadata() };
return std::pair{ std::unique_ptr<AST::Statement>{ret}, true };
}
if (inner.peek().type == token::Type::ContinueKeyword) {
inner.next();
stream.m_position = inner.m_position;
auto ret = new AST::ContinueStatement{ before_meta + stream.metadata() };
return std::pair{ std::unique_ptr<AST::Statement>{ret}, true };
}
if (inner.peek().type == token::Type::Symbol && inner.peek().content == "{") {
inner.expect(token::Type::Symbol, "{");
std::vector<std::unique_ptr<AST::Statement>> statements{};
Scope inner_scope{ scope };
while (inner.peek().content != "}") {
auto res = parse_statement(inner, inner_scope).unwrap();
if (res.second)
inner.expect(token::Type::Symbol, ";");
statements.push_back(std::move(res.first));
}
inner.expect(token::Type::Symbol, "}");
stream.m_position = inner.m_position;
auto ret = new AST::CompoundStatement{ before_meta + stream.metadata(),std::move(statements) };
return std::pair{ std::unique_ptr<AST::Statement>{ret}, false };
}
if (inner.peek().type == token::Type::ReturnKeyword) { if (inner.peek().type == token::Type::ReturnKeyword) {
inner.next(); inner.next();
auto expression = parse_expression(inner, scope).unwrap(); auto expression = parse_expression(inner, scope).unwrap();

View File

@ -63,6 +63,10 @@ namespace token {
return "For"; return "For";
case token::Type::WhileKeyword: case token::Type::WhileKeyword:
return "While"; return "While";
case token::Type::BreakKeyword:
return "Break";
case token::Type::ContinueKeyword:
return "Continue";
case token::Type::Whitespace: case token::Type::Whitespace:
return "Whitespace"; return "Whitespace";
@ -257,6 +261,12 @@ namespace token {
else if (content == "while") { else if (content == "while") {
type = token::Type::WhileKeyword; type = token::Type::WhileKeyword;
} }
else if (content == "break") {
type = token::Type::BreakKeyword;
}
else if (content == "continue") {
type = token::Type::ContinueKeyword;
}
tokens.push_back(token::Token{ type, content, meta + content.size() }); tokens.push_back(token::Token{ type, content, meta + content.size() });
} }
else if (iswhitespace(c)) { else if (iswhitespace(c)) {

View File

@ -18,6 +18,8 @@ namespace token {
ElseKeyword, ElseKeyword,
ForKeyword, ForKeyword,
WhileKeyword, WhileKeyword,
BreakKeyword,
ContinueKeyword,
Whitespace, Whitespace,
Comment, Comment,

View File

@ -646,6 +646,7 @@ namespace AST {
new types::FundamentalType{ false, types::FundamentalTypeKind::Bool } }; new types::FundamentalType{ false, types::FundamentalTypeKind::Bool } };
typecheck::Scope inner_scope{ scope }; typecheck::Scope inner_scope{ scope };
inner_scope.loop_depth += 1;
if (this->m_init) if (this->m_init)
(*this->m_init)->typecheck(state, inner_scope); (*this->m_init)->typecheck(state, inner_scope);
@ -674,6 +675,7 @@ namespace AST {
new types::FundamentalType{ false, types::FundamentalTypeKind::Bool } }; new types::FundamentalType{ false, types::FundamentalTypeKind::Bool } };
typecheck::Scope inner_scope{ scope }; typecheck::Scope inner_scope{ scope };
inner_scope.loop_depth += 1;
if (this->m_cond) { if (this->m_cond) {
auto cond_ty = (*this->m_cond)->typecheck(state, inner_scope, bool_ty).type; auto cond_ty = (*this->m_cond)->typecheck(state, inner_scope, bool_ty).type;
@ -700,10 +702,18 @@ namespace AST {
} }
void BreakStatement::typecheck_preprocess(typecheck::Scope&) {} void BreakStatement::typecheck_preprocess(typecheck::Scope&) {}
void BreakStatement::typecheck(typecheck::State&, typecheck::Scope&) {} void BreakStatement::typecheck(typecheck::State& state, typecheck::Scope& scope) {
if (scope.loop_depth <= 0) {
state.errors.push_back(CompileError("Can not use break outside of a loop", this->m_meta));
}
}
void ContinueStatement::typecheck_preprocess(typecheck::Scope&) {} void ContinueStatement::typecheck_preprocess(typecheck::Scope&) {}
void ContinueStatement::typecheck(typecheck::State&, typecheck::Scope&) {} void ContinueStatement::typecheck(typecheck::State& state, typecheck::Scope& scope) {
if (scope.loop_depth <= 0) {
state.errors.push_back(CompileError("Can not use continue outside of a loop", this->m_meta));
}
}
void Function::typecheck_preprocess(typecheck::Scope& scope) { void Function::typecheck_preprocess(typecheck::Scope& scope) {
this->m_return_ty = refresh_type(scope, this->m_return_ty); this->m_return_ty = refresh_type(scope, this->m_return_ty);

View File

@ -13,6 +13,7 @@ namespace typecheck {
std::map<std::string, std::shared_ptr<types::Type>> symbols; std::map<std::string, std::shared_ptr<types::Type>> symbols;
std::map<std::string, std::shared_ptr<types::Type>> structs; std::map<std::string, std::shared_ptr<types::Type>> structs;
std::optional<std::shared_ptr<types::Type>> return_ty; std::optional<std::shared_ptr<types::Type>> return_ty;
int loop_depth;
}; };
struct State { struct State {

View File

@ -151,7 +151,7 @@ namespace types {
std::pair<llvm::Value*, std::shared_ptr<Type>> PointerType::load(codegen::Builder& builder, llvm::Value* ptr, codegen::TypeMap& structs) { std::pair<llvm::Value*, std::shared_ptr<Type>> PointerType::load(codegen::Builder& builder, llvm::Value* ptr, codegen::TypeMap& structs) {
return std::pair( return std::pair(
builder.builder->CreateLoad(this->m_inner->codegen(builder, structs), ptr), builder.builder->CreateLoad(this->m_inner->codegen(builder, structs), ptr, "load"),
this->m_inner this->m_inner
); );
} }

9
test.c
View File

@ -57,12 +57,17 @@ int main() {
printf("2d array: %d!\n", twod_array[0][0]); printf("2d array: %d!\n", twod_array[0][0]);
// Test for-loops // Test for-loops
for (int counter = 0; counter < 10; counter++) for (int counter = 0; counter < 10; counter++) {
if (counter < 5)
continue;
printf("for-counter: %d\n", counter); printf("for-counter: %d\n", counter);
}
// Test while-loops // Test while-loops
int counter = 0; int counter = 0;
while (counter < 10) { while (1) {
if (counter > 10)
break;
printf("while-counter: %d\n", counter++); printf("while-counter: %d\n", counter++);
} }