diff --git a/src/ast.cpp b/src/ast.cpp index f2483a3..ed38c6a 100644 --- a/src/ast.cpp +++ b/src/ast.cpp @@ -142,10 +142,10 @@ namespace AST { out << "for ("; if (this->m_init) out << (*this->m_init)->formatted(); - out << ";"; + out << "; "; if (this->m_cond) out << (*this->m_cond)->formatted(); - out << ";"; + out << "; "; if (this->m_after) out << (*this->m_after)->formatted(); out << ")"; @@ -154,6 +154,17 @@ namespace AST { return out.str(); } + std::string WhileStatement::formatted() { + std::stringstream out{ "" }; + out << "while ("; + if (this->m_cond) + out << (*this->m_cond)->formatted(); + out << ")"; + + out << "\n then " << this->m_loop->formatted(); + return out.str(); + } + std::string ReturnStatement::formatted() { std::stringstream out{ "" }; out << "return "; diff --git a/src/ast.h b/src/ast.h index 11db249..de19e41 100644 --- a/src/ast.h +++ b/src/ast.h @@ -453,6 +453,26 @@ namespace AST { virtual void typecheck(typecheck::State& state, typecheck::Scope& scope) override; }; + class WhileStatement : public Statement { + private: + std::optional> m_cond; + std::unique_ptr m_loop; + public: + WhileStatement(token::Metadata meta, + std::optional> cond, + std::unique_ptr loop) + : Statement{ meta } + , m_cond{ std::move(cond) } + , m_loop{ std::move(loop) } { + } + virtual ~WhileStatement() override = default; + virtual std::string formatted() override; + virtual void codegen(codegen::Builder& builder, codegen::Scope& scope, codegen::StackAllocator& allocator) override; + virtual void codegen_alloca(codegen::StackAllocator& allocator) override; + virtual void typecheck_preprocess(typecheck::Scope& scope) override; + virtual void typecheck(typecheck::State& state, typecheck::Scope& scope) override; + }; + class TopLevelStatement : public Node { public: TopLevelStatement(token::Metadata meta) : Node{ meta } {} diff --git a/src/codegen.cpp b/src/codegen.cpp index ab3ccec..466afb7 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -596,6 +596,15 @@ namespace AST { builder.builder->SetInsertPoint(after_bb); } + void WhileStatement::codegen(codegen::Builder& builder, codegen::Scope&, codegen::StackAllocator&) { + if (!builder.block) + return; + + builder.builder->SetInsertPoint(builder.block); + + throw CompileError("TODO", this->m_meta); + } + void Function::codegen(codegen::Builder& builder, codegen::Scope& scope) { std::shared_ptr ret_ty_ptr{ this->m_return_ty }; diff --git a/src/parsing.cpp b/src/parsing.cpp index 3c20e3f..74141af 100644 --- a/src/parsing.cpp +++ b/src/parsing.cpp @@ -598,6 +598,30 @@ namespace parsing { }; return std::pair{ std::unique_ptr{ statement }, false }; } + else if (inner.peek().type == token::Type::WhileKeyword) { + inner.next(); + inner.expect(token::Type::Symbol, "("); + + std::optional> cond; + + if (inner.peek().content != ")") + cond = parse_expression(inner, scope).unwrap(); + inner.expect(token::Type::Symbol, ")"); + + auto loop_res = parse_statement(inner, scope).unwrap(); + if (loop_res.second) + inner.expect(token::Type::Symbol, ";"); + auto loop = std::move(loop_res.first); + + stream.m_position = inner.m_position; + + auto statement = new AST::WhileStatement{ + before_meta + stream.metadata(), + std::move(cond), + std::move(loop), + }; + return std::pair{ std::unique_ptr{ statement }, false }; + } else if (auto init = parse_init_statement(inner, scope); init.ok()) { stream.m_position = inner.m_position; return std::pair{ std::unique_ptr{ init.unwrap() }, true }; diff --git a/src/stack_allocator.cpp b/src/stack_allocator.cpp index 7f8f1ef..92a56e9 100644 --- a/src/stack_allocator.cpp +++ b/src/stack_allocator.cpp @@ -103,4 +103,10 @@ namespace AST { (*this->m_after)->codegen_alloca(allocator); this->m_loop->codegen_alloca(allocator); } + + void WhileStatement::codegen_alloca(codegen::StackAllocator& allocator) { + if (this->m_cond) + (*this->m_cond)->codegen_alloca(allocator); + this->m_loop->codegen_alloca(allocator); + } } \ No newline at end of file diff --git a/src/tokens.cpp b/src/tokens.cpp index 96395a1..37147d3 100644 --- a/src/tokens.cpp +++ b/src/tokens.cpp @@ -61,6 +61,8 @@ namespace token { return "Else"; case token::Type::ForKeyword: return "For"; + case token::Type::WhileKeyword: + return "While"; case token::Type::Whitespace: return "Whitespace"; @@ -227,6 +229,9 @@ namespace token { else if (content == "for") { type = token::Type::ForKeyword; } + else if (content == "while") { + type = token::Type::WhileKeyword; + } tokens.push_back(token::Token{ type, content, meta + content.size() }); } else if (iswhitespace(c)) { diff --git a/src/tokens.h b/src/tokens.h index 619fa7b..6474845 100644 --- a/src/tokens.h +++ b/src/tokens.h @@ -17,6 +17,7 @@ namespace token { IfKeyword, ElseKeyword, ForKeyword, + WhileKeyword, Whitespace, diff --git a/src/typechecker.cpp b/src/typechecker.cpp index 4f255c0..372f79f 100644 --- a/src/typechecker.cpp +++ b/src/typechecker.cpp @@ -663,6 +663,28 @@ namespace AST { this->m_loop->typecheck(state, inner_scope); } + void WhileStatement::typecheck_preprocess(typecheck::Scope& scope) { + if (this->m_cond) + (*this->m_cond)->typecheck_preprocess(scope); + this->m_loop->typecheck_preprocess(scope); + } + + void WhileStatement::typecheck(typecheck::State& state, typecheck::Scope& scope) { + auto bool_ty = std::shared_ptr{ + new types::FundamentalType{ false, types::FundamentalTypeKind::Bool } }; + + typecheck::Scope inner_scope{ scope }; + + if (this->m_cond) { + auto cond_ty = (*this->m_cond)->typecheck(state, inner_scope, bool_ty).type; + + auto check_res = check_type(state, cond_ty, bool_ty); + this->m_cond = handle_res(std::move(*this->m_cond), check_res, state); + } + + this->m_loop->typecheck(state, inner_scope); + } + void Function::typecheck_preprocess(typecheck::Scope& scope) { this->m_return_ty = refresh_type(scope, this->m_return_ty); for (auto& param : this->m_params) { diff --git a/test.c b/test.c index 5c5c5f8..2341b71 100644 --- a/test.c +++ b/test.c @@ -54,5 +54,9 @@ int main() { for (int counter = 0; counter < 10; counter++) printf("counter: %d\n", counter); + int counter = 0; + while (counter < 10) + printf("counter: %d\n", counter++); + return 0; } \ No newline at end of file