From 7d3518d32e1020fba5960a9988b821e8ede9a39a Mon Sep 17 00:00:00 2001 From: gaborhadhazy Date: Thu, 30 May 2024 19:59:36 +0100 Subject: [PATCH 01/16] base range codegen --- Include/codegen/codegen.h | 3 + src/ast/tree.cc | 8 +++ src/codegen/codegen.cc | 132 +++++++++++++++++++++++++++++++------- src/sema.cc | 10 +++ 4 files changed, 130 insertions(+), 23 deletions(-) diff --git a/Include/codegen/codegen.h b/Include/codegen/codegen.h index 6badfca..dc0f398 100644 --- a/Include/codegen/codegen.h +++ b/Include/codegen/codegen.h @@ -114,6 +114,9 @@ class DonsusCodeGenerator { utility::handle &ast, utility::handle &table); + llvm::Value *visit(donsus_ast::range_for_loop &ac_ast, + utility::handle &table); + llvm::Value *visit(donsus_ast::else_statement &ast, utility::handle &table); diff --git a/src/ast/tree.cc b/src/ast/tree.cc index ad36620..40a7438 100644 --- a/src/ast/tree.cc +++ b/src/ast/tree.cc @@ -103,6 +103,14 @@ void tree::traverse_nodes( break; } + case donsus_ast::donsus_node_type::DONSUS_RANGE_FOR_LOOP: { + auto stuff = n->get(); + for (auto &children : stuff.body) { + traverse_nodes(visit, assign_type_to_node, sym, codegen, children); + } + break; + } + case donsus_ast::donsus_node_type::DONSUS_FUNCTION_ARG: { auto stuff = n->get(); sym->add(stuff.identifier_name, diff --git a/src/codegen/codegen.cc b/src/codegen/codegen.cc index ac23cc3..3a83fd0 100644 --- a/src/codegen/codegen.cc +++ b/src/codegen/codegen.cc @@ -220,6 +220,10 @@ DonsusCodeGenerator::compile(utility::handle &n, return visit(n->get(), table); } + case donsus_ast::donsus_node_type::DONSUS_RANGE_FOR_LOOP: { + return visit(n->get(), table); + } + case donsus_ast::donsus_node_type::DONSUS_FUNCTION_DEF: { return visit(n->get(), table); } @@ -289,21 +293,14 @@ DonsusCodeGenerator::DonsusCodeGenerator( create_entry_point(); llvm::Function *TheFunction = TheModule->getFunction("main"); + // // assert here + llvm::BasicBlock *entry = llvm::BasicBlock::Create(*TheContext, "entry_point", TheFunction); main_block = entry; Builder->SetInsertPoint(entry); - load_built_in(); } -void DonsusCodeGenerator::load_built_in() { - // declare built-in functions - - /*llvm::FunctionType *FT = - llvm::FunctionType::get(llvm::Type::getVoidTy(*TheContext), nullptr, false); - llvm::Function *F = llvm::Function::Create(FT, - llvm::Function::ExternalLinkage, "test", *TheModule);*/ -} llvm::Value *DonsusCodeGenerator::visit(utility::handle &ast, donsus_ast::variable_decl &ca_ast, utility::handle &table, @@ -666,6 +663,68 @@ DonsusCodeGenerator::visit(donsus_ast::if_statement &ac_ast, return llvm::ConstantInt::get(*TheContext, llvm::APInt(32, 0)); } +llvm::Value * +DonsusCodeGenerator::visit(donsus_ast::range_for_loop &ac_ast, + utility::handle &table) { + llvm::Function *TheFunction = Builder->GetInsertBlock()->getParent(); + + // Create blocks for the loop + llvm::BasicBlock *PreheaderBB = Builder->GetInsertBlock(); + llvm::BasicBlock *LoopCondBB = + llvm::BasicBlock::Create(*TheContext, "for.cond", TheFunction); + llvm::BasicBlock *LoopBodyBB = + llvm::BasicBlock::Create(*TheContext, "for.body", TheFunction); + llvm::BasicBlock *LoopIncBB = + llvm::BasicBlock::Create(*TheContext, "for.inc", TheFunction); + llvm::BasicBlock *AfterBB = + llvm::BasicBlock::Create(*TheContext, "for.end", TheFunction); + + // Allocate and initialize the loop variable + llvm::AllocaInst *Alloca = Builder->CreateAlloca( + llvm::Type::getInt32Ty(*TheContext), nullptr, ac_ast.loop_variable); + llvm::Value *StartVal = compile(ac_ast.start, table); + Builder->CreateStore(StartVal, Alloca); + + // Jump to the loop condition block + Builder->CreateBr(LoopCondBB); + Builder->SetInsertPoint(LoopCondBB); + + // Load the current value of the loop variable + llvm::Value *CurVal = Builder->CreateLoad(Alloca->getAllocatedType(), Alloca); + + // Compare the loop variable with the end value + llvm::Value *EndVal = compile(ac_ast.end, table); + llvm::Value *Cond = Builder->CreateICmpSLT(CurVal, EndVal); + + // Branch based on the comparison + Builder->CreateCondBr(Cond, LoopBodyBB, AfterBB); + + // Generate the loop body + Builder->SetInsertPoint(LoopBodyBB); + for (auto &bodyNode : ac_ast.body) { + compile(bodyNode, table); + } + + // After the body, jump to the increment block + Builder->CreateBr(LoopIncBB); + Builder->SetInsertPoint(LoopIncBB); + + // Increment the loop variable + llvm::Value *StepVal = + llvm::ConstantInt::get(*TheContext, llvm::APInt(32, 1)); + llvm::Value *NextVal = Builder->CreateAdd(CurVal, StepVal); + Builder->CreateStore(NextVal, Alloca); + + // Jump back to the loop condition block + Builder->CreateBr(LoopCondBB); + + // Set the insertion point to the after block + Builder->SetInsertPoint(AfterBB); + + // Return value after the loop + return llvm::ConstantInt::get(*TheContext, llvm::APInt(32, 0)); +} + llvm::Value * DonsusCodeGenerator::visit(donsus_ast::else_statement &ast, utility::handle &table) {} @@ -860,10 +919,26 @@ DonsusCodeGenerator::visit(utility::handle &ast, std::string format_string{}; for (auto node : ast->children) { + if (!is_expression(node)) { + DonsusSymTable::sym sym = sym_from_node(node, table); + if (sym.type.type_un == DONSUS_TYPE::TYPE_STATIC_ARRAY || + sym.type.type_un == DONSUS_TYPE::TYPE_DYNAMIC_ARRAY || + sym.type.type_un == DONSUS_TYPE::TYPE_FIXED_ARRAY) { + + for (size_t i = 0; i < sym.array.insts.size(); ++i) { + format_string.append(printf_format(sym.array.type)); + } + continue; + } + // not nice: I know + // not expression but not an array might remove this + format_string.append(printf_format(node->real_type)); - format_string.append(printf_format(node->real_type)); - } + } else { + format_string.append(printf_format(node->real_type)); + } + } Argsv.push_back(Builder->CreateGlobalString(format_string)); for (auto node : ast->children) { @@ -874,7 +949,6 @@ DonsusCodeGenerator::visit(utility::handle &ast, if (cur_value->getType()->isPointerTy() && node->type.type == donsus_ast::donsus_node_type::underlying::DONSUS_ARRAY_ACCESS) { - Argsv.push_back( Builder->CreateLoad(map_type(node->real_type), cur_value)); } else { @@ -884,6 +958,18 @@ DonsusCodeGenerator::visit(utility::handle &ast, } DonsusSymTable::sym sym = sym_from_node(node, table); + if (sym.type.type_un == DONSUS_TYPE::TYPE_STATIC_ARRAY || + sym.type.type_un == DONSUS_TYPE::TYPE_DYNAMIC_ARRAY || + sym.type.type_un == DONSUS_TYPE::TYPE_FIXED_ARRAY) { + for (auto i : sym.array.insts) { + if (!i->getType()->isPointerTy()) { + Argsv.push_back(i); + continue; + } + Argsv.push_back(Builder->CreateLoad(map_type(sym.array.type), i)); + } + continue; + } if (sym.type.type_un == DONSUS_TYPE::TYPE_F32) { // https://stackoverflow.com/questions/63144506/printf-doesnt-work-for-floats-in-llvm-ir#comment111685194_63156309 llvm::Value *loadedFloatValue = @@ -974,15 +1060,8 @@ DonsusCodeGenerator::visit(utility::handle &ast, /* * llvm::ArrayType::get(map_type(make_type(type)) * */ - int size{}; - // Todo: runtime dynamic alloc lib - if (ca_ast.array_type == donsus_ast::ArrayType::DYNAMIC) { - size = 10; - } else { - size = ca_ast.size; - } llvm::ArrayType *arrayType = - llvm::ArrayType::get(map_type(make_type(type)), size); + llvm::ArrayType::get(map_type(make_type(type)), ca_ast.size); // create array DonsusSymTable::sym::donsus_array don_a; @@ -1065,11 +1144,18 @@ llvm::Value *DonsusCodegen::DonsusCodeGenerator::visit( DonsusSymTable::sym symbol = table->get(ca_ast.identifier_name); llvm::Value *value; - + /* if (!ast->children.empty()) {*/ + // arr[i] = smt; std::vector indxList1{}; indxList1.push_back(llvm::ConstantInt::get(*TheContext, llvm::APInt(32, 0))); - value = - Builder->CreateGEP(map_type(symbol.array.type), symbol.inst, indxList1); + indxList1.push_back(compile(ca_ast.index, table)); + + value = Builder->CreateGEP(symbol.array.array_type, symbol.inst, indxList1); + + /*} */ /*else { + // arr[i] + return nullptr; + }*/ return value; } llvm::Type *DonsusCodegen::DonsusCodeGenerator::map_type(DONSUS_TYPE type) { diff --git a/src/sema.cc b/src/sema.cc index eafcc7f..36f46fb 100644 --- a/src/sema.cc +++ b/src/sema.cc @@ -197,6 +197,16 @@ auto assign_type_to_node(utility::handle node, break; } + case donsus_ast::donsus_node_type::DONSUS_RANGE_FOR_LOOP: { + for (auto &n : node->get().body) { + if (n->type.type == donsus_ast::donsus_node_type::DONSUS_ASSIGNMENT) { + continue; + } + assign_type_to_node(n, table, global_table); + } + break; + } + case donsus_ast::donsus_node_type::DONSUS_IF_STATEMENT: { for (auto &n : node->get().body) { if (n->type.type == donsus_ast::donsus_node_type::DONSUS_ASSIGNMENT) { From 24cf513ba826feacc86150b3216aa05d69d07af6 Mon Sep 17 00:00:00 2001 From: gaborhadhazy Date: Sat, 1 Jun 2024 22:32:23 +0100 Subject: [PATCH 02/16] for loop potential UB --- Include/codegen/codegen.h | 3 +++ src/ast/tree.cc | 8 ++++++++ src/codegen/codegen.cc | 28 ++++++++++++++++++++++++++++ src/sema.cc | 10 ++++++++++ 4 files changed, 49 insertions(+) diff --git a/Include/codegen/codegen.h b/Include/codegen/codegen.h index dc0f398..706fc89 100644 --- a/Include/codegen/codegen.h +++ b/Include/codegen/codegen.h @@ -117,6 +117,9 @@ class DonsusCodeGenerator { llvm::Value *visit(donsus_ast::range_for_loop &ac_ast, utility::handle &table); + llvm::Value *visit(donsus_ast::array_for_loop &ac_ast, + utility::handle &table); + llvm::Value *visit(donsus_ast::else_statement &ast, utility::handle &table); diff --git a/src/ast/tree.cc b/src/ast/tree.cc index 40a7438..7a35507 100644 --- a/src/ast/tree.cc +++ b/src/ast/tree.cc @@ -111,6 +111,14 @@ void tree::traverse_nodes( break; } + case donsus_ast::donsus_node_type::DONSUS_ARRAY_FOR_LOOP: { + auto stuff = n->get(); + for (auto &children : stuff.body) { + traverse_nodes(visit, assign_type_to_node, sym, codegen, children); + } + break; + } + case donsus_ast::donsus_node_type::DONSUS_FUNCTION_ARG: { auto stuff = n->get(); sym->add(stuff.identifier_name, diff --git a/src/codegen/codegen.cc b/src/codegen/codegen.cc index 3a83fd0..16c7040 100644 --- a/src/codegen/codegen.cc +++ b/src/codegen/codegen.cc @@ -223,6 +223,9 @@ DonsusCodeGenerator::compile(utility::handle &n, case donsus_ast::donsus_node_type::DONSUS_RANGE_FOR_LOOP: { return visit(n->get(), table); } + case donsus_ast::donsus_node_type::DONSUS_ARRAY_FOR_LOOP: { + return visit(n->get(), table); + } case donsus_ast::donsus_node_type::DONSUS_FUNCTION_DEF: { return visit(n->get(), table); @@ -725,6 +728,31 @@ DonsusCodeGenerator::visit(donsus_ast::range_for_loop &ac_ast, return llvm::ConstantInt::get(*TheContext, llvm::APInt(32, 0)); } +llvm::Value * +DonsusCodeGenerator::visit(donsus_ast::array_for_loop &ac_ast, + utility::handle &table) { + llvm::Function *TheFunction = Builder->GetInsertBlock()->getParent(); + // Create blocks for the loop + llvm::BasicBlock *PreheaderBB = Builder->GetInsertBlock(); + llvm::BasicBlock *LoopCondBB = + llvm::BasicBlock::Create(*TheContext, "for.cond", TheFunction); + llvm::BasicBlock *LoopBodyBB = + llvm::BasicBlock::Create(*TheContext, "for.body", TheFunction); + llvm::BasicBlock *LoopIncBB = + llvm::BasicBlock::Create(*TheContext, "for.inc", TheFunction); + llvm::BasicBlock *AfterBB = + llvm::BasicBlock::Create(*TheContext, "for.end", TheFunction); + + // Allocate and initialize the loop variable + llvm::AllocaInst *Alloca = Builder->CreateAlloca( + llvm::Type::getInt32Ty(*TheContext), nullptr, ac_ast.loop_variable); + + // Get the array from the symbol table + DonsusSymTable::sym sym = table->get(ac_ast.array_name); + + return llvm::ConstantInt::get(*TheContext, llvm::APInt(32, 0)); +} + llvm::Value * DonsusCodeGenerator::visit(donsus_ast::else_statement &ast, utility::handle &table) {} diff --git a/src/sema.cc b/src/sema.cc index 36f46fb..6625af9 100644 --- a/src/sema.cc +++ b/src/sema.cc @@ -207,6 +207,16 @@ auto assign_type_to_node(utility::handle node, break; } + case donsus_ast::donsus_node_type::DONSUS_ARRAY_FOR_LOOP: { + for (auto &n : node->get().body) { + if (n->type.type == donsus_ast::donsus_node_type::DONSUS_ASSIGNMENT) { + continue; + } + assign_type_to_node(n, table, global_table); + } + break; + } + case donsus_ast::donsus_node_type::DONSUS_IF_STATEMENT: { for (auto &n : node->get().body) { if (n->type.type == donsus_ast::donsus_node_type::DONSUS_ASSIGNMENT) { From 207b32faa42636d57d36f6e35c9b01ce96a87e89 Mon Sep 17 00:00:00 2001 From: gaborhadhazy Date: Sun, 2 Jun 2024 09:19:32 +0100 Subject: [PATCH 03/16] loop variable can be used inside of for loops --- src/ast/tree.cc | 3 +++ src/codegen/codegen.cc | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/src/ast/tree.cc b/src/ast/tree.cc index 7a35507..28cee0d 100644 --- a/src/ast/tree.cc +++ b/src/ast/tree.cc @@ -105,6 +105,9 @@ void tree::traverse_nodes( case donsus_ast::donsus_node_type::DONSUS_RANGE_FOR_LOOP: { auto stuff = n->get(); + // add loop variable to the symbol table + sym->add(stuff.loop_variable, + make_type(donsus_token_kind::DONSUS_BASIC_INT)); for (auto &children : stuff.body) { traverse_nodes(visit, assign_type_to_node, sym, codegen, children); } diff --git a/src/codegen/codegen.cc b/src/codegen/codegen.cc index 16c7040..8eed93b 100644 --- a/src/codegen/codegen.cc +++ b/src/codegen/codegen.cc @@ -704,6 +704,10 @@ DonsusCodeGenerator::visit(donsus_ast::range_for_loop &ac_ast, // Generate the loop body Builder->SetInsertPoint(LoopBodyBB); + + // Reload the current value of the loop variable + table->setInst(ac_ast.loop_variable, Alloca); + for (auto &bodyNode : ac_ast.body) { compile(bodyNode, table); } From aedd9d39923283f8c1999eb991e50aef2c612923 Mon Sep 17 00:00:00 2001 From: gaborhadhazy Date: Mon, 3 Jun 2024 20:20:53 +0100 Subject: [PATCH 04/16] for loops with array --- src/codegen/codegen.cc | 68 ++++++++++++++++++++++++++++++++++++++++++ src/parser.cc | 4 ++- 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/src/codegen/codegen.cc b/src/codegen/codegen.cc index 8eed93b..a0d8e19 100644 --- a/src/codegen/codegen.cc +++ b/src/codegen/codegen.cc @@ -736,6 +736,7 @@ llvm::Value * DonsusCodeGenerator::visit(donsus_ast::array_for_loop &ac_ast, utility::handle &table) { llvm::Function *TheFunction = Builder->GetInsertBlock()->getParent(); + // Create blocks for the loop llvm::BasicBlock *PreheaderBB = Builder->GetInsertBlock(); llvm::BasicBlock *LoopCondBB = @@ -754,6 +755,73 @@ DonsusCodeGenerator::visit(donsus_ast::array_for_loop &ac_ast, // Get the array from the symbol table DonsusSymTable::sym sym = table->get(ac_ast.array_name); + // Ensure the array is properly typed and accessed + llvm::ArrayType *ArrayTy = llvm::ArrayType::get( + llvm::Type::getInt32Ty(*TheContext), + sym.array.num_of_elems); // Adjust based on actual member + llvm::AllocaInst *ArrayAlloca = + Builder->CreateAlloca(ArrayTy, nullptr, ac_ast.array_name); + + // Store the array elements in the allocated space + for (size_t i = 0; i < sym.array.num_of_elems; + ++i) { // Adjust based on actual member + llvm::Value *Idx = llvm::ConstantInt::get(*TheContext, llvm::APInt(32, i)); + } + + // Initialize loop variable to 0 + Builder->CreateStore(llvm::ConstantInt::get(*TheContext, llvm::APInt(32, 0)), + Alloca); + Builder->CreateBr(LoopCondBB); + + // Loop condition block + Builder->SetInsertPoint(LoopCondBB); + llvm::Value *CurVar = Builder->CreateLoad(Alloca->getAllocatedType(), Alloca); + llvm::Value *Cond = Builder->CreateICmpSLT( + CurVar, + llvm::ConstantInt::get( + *TheContext, + llvm::APInt( + 32, sym.array.num_of_elems))); // Adjust based on actual member + Builder->CreateCondBr(Cond, LoopBodyBB, AfterBB); + + // Loop body block + Builder->SetInsertPoint(LoopBodyBB); + llvm::Value *ArrayIdx = + Builder->CreateLoad(Alloca->getAllocatedType(), Alloca); + llvm::Value *Idx = llvm::ConstantInt::get( + *TheContext, + llvm::APInt( + 32, 0)); // Assuming you're accessing the first element of ArrayAlloca + llvm::Value *ElemPtr = + Builder->CreateGEP(ArrayTy, ArrayAlloca, {Idx, ArrayIdx}); // Adjust based + // on actual + // member and + llvm::Value *Elem = Builder->CreateLoad(ElemPtr->getType(), ElemPtr); + + table->setInst(ac_ast.loop_variable, Alloca); + + // Handle loop body as needed + for (auto &bodyNode : ac_ast.body) { + compile(bodyNode, table); + } + + // After the body, jump to the increment block + Builder->CreateBr(LoopIncBB); + Builder->SetInsertPoint(LoopIncBB); + + // Increment the loop variable + llvm::Value *StepVal = + llvm::ConstantInt::get(*TheContext, llvm::APInt(32, 1)); + llvm::Value *NextVal = Builder->CreateAdd(CurVar, StepVal); + Builder->CreateStore(NextVal, Alloca); + + // Jump back to the loop condition block + Builder->CreateBr(LoopCondBB); + + // Set the insertion point to the after block + Builder->SetInsertPoint(AfterBB); + + // Return value after the loop return llvm::ConstantInt::get(*TheContext, llvm::APInt(32, 0)); } diff --git a/src/parser.cc b/src/parser.cc index b5477ca..f2d0b56 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -966,7 +966,9 @@ auto DonsusParser::donsus_array_definition( // move to the next token parse_result array_definition = create_array_definition( donsus_ast::donsus_node_type::DONSUS_ARRAY_DEFINITION, 10); - + array_definition->get().size = 0; + array_definition->get().number_of_elements = 0; + array_definition->get().type = DONSUS_NAME; auto &expression = array_definition->get(); expression.identifier_name = declaration->get().identifier_name; From 7adc043649aee0eadd2ce9c04e6d355d71169c10 Mon Sep 17 00:00:00 2001 From: gaborhadhazy Date: Mon, 3 Jun 2024 21:47:10 +0100 Subject: [PATCH 05/16] get rid of unneccessary comments and lines --- src/codegen/codegen.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/src/codegen/codegen.cc b/src/codegen/codegen.cc index a0d8e19..1f1210a 100644 --- a/src/codegen/codegen.cc +++ b/src/codegen/codegen.cc @@ -738,7 +738,6 @@ DonsusCodeGenerator::visit(donsus_ast::array_for_loop &ac_ast, llvm::Function *TheFunction = Builder->GetInsertBlock()->getParent(); // Create blocks for the loop - llvm::BasicBlock *PreheaderBB = Builder->GetInsertBlock(); llvm::BasicBlock *LoopCondBB = llvm::BasicBlock::Create(*TheContext, "for.cond", TheFunction); llvm::BasicBlock *LoopBodyBB = From 6fd0ce3238c92b9cc0cb67fbb225283ce188858b Mon Sep 17 00:00:00 2001 From: gaborhadhazy Date: Mon, 3 Jun 2024 20:20:53 +0100 Subject: [PATCH 06/16] for loops with array --- src/parser.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/parser.cc b/src/parser.cc index 60ed5ea..455e939 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -988,10 +988,8 @@ auto DonsusParser::donsus_array_definition( array_definition->get().number_of_elements = 0; array_definition->get().type = DONSUS_NAME; - array_definition->start_offset_ast = cur_token; - auto &expression = array_definition->get(); expression.identifier_name = declaration->get().identifier_name; From f6c59e400ea0fae6b502bb4aaca8581bbc0192ca Mon Sep 17 00:00:00 2001 From: gaborhadhazy Date: Mon, 3 Jun 2024 20:20:53 +0100 Subject: [PATCH 07/16] for loops with array --- src/parser.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/parser.cc b/src/parser.cc index 455e939..ed7783e 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -990,6 +990,9 @@ auto DonsusParser::donsus_array_definition( array_definition->start_offset_ast = cur_token; + array_definition->get().size = 0; + array_definition->get().number_of_elements = 0; + array_definition->get().type = DONSUS_NAME; auto &expression = array_definition->get(); expression.identifier_name = declaration->get().identifier_name; From 207b0ad319a11602f3b63d7e974917d04bcbf422 Mon Sep 17 00:00:00 2001 From: gaborhadhazy Date: Mon, 3 Jun 2024 20:20:53 +0100 Subject: [PATCH 08/16] for loops with array --- src/parser.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/parser.cc b/src/parser.cc index ed7783e..c15e52a 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -988,11 +988,12 @@ auto DonsusParser::donsus_array_definition( array_definition->get().number_of_elements = 0; array_definition->get().type = DONSUS_NAME; - array_definition->start_offset_ast = cur_token; - array_definition->get().size = 0; array_definition->get().number_of_elements = 0; array_definition->get().type = DONSUS_NAME; + + array_definition->start_offset_ast = cur_token; + auto &expression = array_definition->get(); expression.identifier_name = declaration->get().identifier_name; From 48c3a79b6599132820793c5697be34c7aad42684 Mon Sep 17 00:00:00 2001 From: gaborhadhazy Date: Mon, 3 Jun 2024 20:20:53 +0100 Subject: [PATCH 09/16] for loops with array --- src/parser.cc | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/parser.cc b/src/parser.cc index c15e52a..455e939 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -988,10 +988,6 @@ auto DonsusParser::donsus_array_definition( array_definition->get().number_of_elements = 0; array_definition->get().type = DONSUS_NAME; - array_definition->get().size = 0; - array_definition->get().number_of_elements = 0; - array_definition->get().type = DONSUS_NAME; - array_definition->start_offset_ast = cur_token; auto &expression = array_definition->get(); From 2f60a3c744c05be003d91b3cdaade5af96e4e0b7 Mon Sep 17 00:00:00 2001 From: gaborhadhazy Date: Tue, 4 Jun 2024 13:41:21 +0100 Subject: [PATCH 10/16] variable decl errors --- donsus_test/parser/test_functions.cc | 3 +- src/lexer.cc | 13 ++++-- src/parser.cc | 63 +++++++++++++++++++++------- 3 files changed, 57 insertions(+), 22 deletions(-) diff --git a/donsus_test/parser/test_functions.cc b/donsus_test/parser/test_functions.cc index b030b78..3e69b1c 100644 --- a/donsus_test/parser/test_functions.cc +++ b/donsus_test/parser/test_functions.cc @@ -81,13 +81,12 @@ TEST(Functions, FunctionDefinitionParameters) { std::string a = R"( def a(b:int) -> int { return 1; - }; + } )"; DonsusAstFile file; DonsusParser parser = Du_Parse(a, file); DonsusParser::end_result result = parser.donsus_parse(); - utility::handle sym_global = new DonsusSymTable(); result->init_traverse(); diff --git a/src/lexer.cc b/src/lexer.cc index 01ffb71..680a7e2 100644 --- a/src/lexer.cc +++ b/src/lexer.cc @@ -247,7 +247,7 @@ char peek_back_for_char(DonsusParser &parser) { static bool isstart_identifier(char c) { // entry point of an identifier - return isalpha(c) || c == '_'; + return (isalpha(c) != 0) || c == '_'; } static bool iscontinue_identifier(char c) { @@ -329,13 +329,18 @@ std::string donsus_float(DonsusParser &parser, donsus_token &token, return fractional_part; } -static std::string next_identifier(DonsusParser &parser, donsus_token& token, +static std::string next_identifier(DonsusParser &parser, donsus_token &token, unsigned int start_pos) { + // Check if the current character is a continue identifier + if (!iscontinue_identifier(parser.lexer.cur_char)) { + parser.donsus_syntax_error( + nullptr, parser.lexer.cur_column, parser.lexer.cur_line, + "Invalid identifier: '" + std::string(1, parser.lexer.cur_char) + "'"); + } + // Proceed with the while loop if the initial check passes while (iscontinue_identifier(parser.lexer.cur_char)) { - token.length++; - eat(parser); } diff --git a/src/parser.cc b/src/parser.cc index 455e939..5e75115 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -560,20 +560,24 @@ auto DonsusParser::donsus_parse() -> end_result { donsus_variable_multi_decl_def(); } else { donsus_syntax_error(nullptr, cur_token.column, cur_token.line, - "Unexpected token: '" + cur_token.value); + "Unexpected token: '" + cur_token.value + "'"); + parse_result tmp; + donsus_tree->add_node(tmp); } } - if (cur_token.kind == DONSUS_IF_KW) { + else if (cur_token.kind == DONSUS_IF_KW) { parse_result result = donsus_if_statement(); if (result->children.empty()) { donsus_syntax_error(&result, cur_token.column, cur_token.line, "Condition wasn't provided for if statement \n"); + parse_result tmp; + donsus_tree->add_node(tmp); } donsus_tree->add_node(result); } - if (cur_token.kind == DONSUS_WHILE_KW) { + else if (cur_token.kind == DONSUS_WHILE_KW) { parse_result result = donsus_while_loop(); if (result->children.empty()) { throw DonsusException( @@ -583,7 +587,7 @@ auto DonsusParser::donsus_parse() -> end_result { donsus_tree->add_node(result); } - if (cur_token.kind == DONSUS_FOR_KW) { + else if (cur_token.kind == DONSUS_FOR_KW) { if (donsus_peek().kind == DONSUS_NAME) { if (donsus_peek(2).kind == DONSUS_COLO) { if (donsus_peek(4).kind == DONSUS_TWO_DOTS) { @@ -599,12 +603,18 @@ auto DonsusParser::donsus_parse() -> end_result { } } - if (cur_token.kind == DONSUS_PRINT_KW) { + else if (cur_token.kind == DONSUS_PRINT_KW) { parse_result result = donsus_print(); donsus_tree->add_node(result); } else if (cur_token.kind == DONSUS_FUNCTION_DEFINITION_KW) { parse_result result = donsus_function_definition(); donsus_tree->add_node(result); + } else if ((cur_token.kind != DONSUS_NEWLINE) && + (cur_token.kind != DONSUS_SEMICOLON)) { + donsus_syntax_error(nullptr, cur_token.column, cur_token.line, + "Unexpected token: '" + cur_token.value + "'"); + parse_result tmp; + donsus_tree->add_node(tmp); } donsus_parser_next(); // move to the next token // if (peek_function_definition()) { @@ -638,11 +648,12 @@ auto DonsusParser::donsus_variable_multi_decl_def() -> void { if (cur_token.kind == DONSUS_COLO) { donsus_parser_next(); if (!(DONSUS_TYPES_LEXER.find(cur_token.value) != - DONSUS_TYPES_LEXER.end())) + DONSUS_TYPES_LEXER.end())) { donsus_syntax_error(nullptr, cur_token.column, cur_token.line, "Type provided: '" + cur_token.value + "' is not valid in the declaration of: '" + identifier_names[0]); + } type = cur_token.kind; } @@ -773,11 +784,11 @@ auto DonsusParser::match_expressions(unsigned int ptp) -> parse_result { } default: { - donsus_syntax_error(nullptr, cur_token.column, cur_token.line, - "Invalid expression provided at token: " + - cur_token.value); - parse_result tmp; - return tmp; + // donsus_syntax_error(nullptr, cur_token.column, cur_token.line, + // "Invalid expression provided at token: " + + // cur_token.value); + // parse_result tmp; + // return tmp; } } } @@ -882,12 +893,18 @@ auto DonsusParser::donsus_variable_decl() -> parse_result { if (type_m == DONSUS_VOID) { donsus_syntax_error(&declaration, cur_token.column, cur_token.line, "Void can't be used as a variable type"); + parse_result tmp; + return tmp; } - if (!(DONSUS_TYPES_LEXER.find(cur_token.value) != DONSUS_TYPES_LEXER.end())) + if (!(DONSUS_TYPES_LEXER.find(cur_token.value) != + DONSUS_TYPES_LEXER.end())) { donsus_syntax_error(&declaration, cur_token.column, cur_token.line, "Type provided: '" + cur_token.value + "' is not valid in the declaration of: '" + expression.identifier_name); + parse_result tmp; + return tmp; + } expression.identifier_type = cur_token.kind; @@ -901,6 +918,8 @@ auto DonsusParser::donsus_variable_decl() -> parse_result { donsus_syntax_error(&declaration, cur_token.column, cur_token.line, "Expected value after equal sign"); + parse_result tmp; + return tmp; } return donsus_variable_definition(declaration); } else if (donsus_peek().kind == DONSUS_LSQB) { @@ -948,12 +967,18 @@ auto DonsusParser::donsus_variable_decl() -> parse_result { } else { // decl only - if (donsus_peek().kind == DONSUS_SEMICOLON) { - donsus_parser_except(DONSUS_SEMICOLON); - // end of declaration + if (donsus_peek().kind == DONSUS_SEMICOLON || + donsus_peek().kind == DONSUS_RPAR || + donsus_peek().kind == DONSUS_COMM) { return declaration; } else { - return declaration; + donsus_syntax_error( + &declaration, cur_token.column, cur_token.line, + "Invalid declaration of '" + expression.identifier_name + + "'. Expected one of the following tokens: ';' (semicolon), ')' " + "(right parenthesis), or ',' (comma)."); + parse_result tmp; + return tmp; } } } @@ -1011,6 +1036,8 @@ auto DonsusParser::donsus_array_definition( } } + donsus_parser_except(DONSUS_SEMICOLON); // expect next token to be ';' + return array_definition; } @@ -1067,6 +1094,8 @@ auto DonsusParser::donsus_function_decl() -> parse_result { donsus_syntax_error(&declaration, cur_token.column, cur_token.line, "Return type wasn't provided for function: '" + expression.func_name); + parse_result tmp; + return tmp; } while (cur_token.kind != DONSUS_LBRACE && cur_token.kind != DONSUS_SEMICOLON) { @@ -1079,6 +1108,8 @@ auto DonsusParser::donsus_function_decl() -> parse_result { "Return type received: '" + cur_token.value + "' in invalid for function: '" + expression.func_name); + parse_result tmp; + return tmp; } donsus_parser_next(); } From e630ffba4a024643296ce6ca8532d62c6b545242 Mon Sep 17 00:00:00 2001 From: gaborhadhazy Date: Wed, 5 Jun 2024 16:56:19 +0100 Subject: [PATCH 11/16] donsus_function_decl error system --- src/parser.cc | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/src/parser.cc b/src/parser.cc index 5e75115..0dfc0d0 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -652,7 +652,7 @@ auto DonsusParser::donsus_variable_multi_decl_def() -> void { donsus_syntax_error(nullptr, cur_token.column, cur_token.line, "Type provided: '" + cur_token.value + "' is not valid in the declaration of: '" + - identifier_names[0]); + identifier_names[0] + "'"); } type = cur_token.kind; @@ -865,6 +865,7 @@ auto DonsusParser::donsus_variable_definition( donsus_parser_next(); parse_result expression = donsus_expr(0); declaration->children.push_back(expression); + donsus_parser_except(DONSUS_SEMICOLON); return declaration; } @@ -901,7 +902,7 @@ auto DonsusParser::donsus_variable_decl() -> parse_result { donsus_syntax_error(&declaration, cur_token.column, cur_token.line, "Type provided: '" + cur_token.value + "' is not valid in the declaration of: '" + - expression.identifier_name); + expression.identifier_name + "'"); parse_result tmp; return tmp; } @@ -1062,14 +1063,27 @@ auto DonsusParser::donsus_function_decl() -> parse_result { return donsus_function_call(); }*/ DONSUS_TYPE tmp{}; - if (donsus_peek().kind == DONSUS_NAME && donsus_peek(2).kind == DONSUS_COLO && - tmp.from_parse(donsus_peek(3).kind) != DONSUS_TYPE::TYPE_UNKNOWN) { - // if we have parameters then the next token is DONSUS_NAME - expression.parameters = donsus_function_signature(); // parse parameters + if (donsus_peek().kind == DONSUS_NAME && donsus_peek(2).kind == DONSUS_COLO) { + if (tmp.from_parse(donsus_peek(3).kind) != DONSUS_TYPE::TYPE_UNKNOWN) { + expression.parameters = donsus_function_signature(); // parse parameters + // if we have parameters then the next token is DONSUS_NAME + } else { + donsus_parser_next(); + donsus_parser_next(); + donsus_parser_next(); + + donsus_syntax_error(&declaration, cur_token.column, cur_token.line, + "Type: '" + cur_token.value + "'" + + " provided for the declaration of '" + + expression.func_name + "'" + " is not valid"); + parse_result tmp; + return tmp; + } } // check if it is - if (tmp.from_parse(donsus_peek(3).kind) == DONSUS_TYPE::TYPE_UNKNOWN) { + if (tmp.from_parse(donsus_peek(3).kind) == DONSUS_TYPE::TYPE_UNKNOWN && + (donsus_peek(2).kind != DONSUS_COLO) && expression.parameters.empty()) { // without parameters /* donsus_peek(3) returns the place where the type is supposed to be if @@ -1093,12 +1107,12 @@ auto DonsusParser::donsus_function_decl() -> parse_result { donsus_syntax_error(&declaration, cur_token.column, cur_token.line, "Return type wasn't provided for function: '" + - expression.func_name); + expression.func_name + "'"); parse_result tmp; return tmp; } while (cur_token.kind != DONSUS_LBRACE && - cur_token.kind != DONSUS_SEMICOLON) { + cur_token.kind != DONSUS_SEMICOLON && cur_token.kind != DONSUS_END) { if (cur_token.kind == DONSUS_COMM) donsus_parser_next(); if (DONSUS_TYPES_LEXER.find(cur_token.value) != DONSUS_TYPES_LEXER.end()) { @@ -1107,7 +1121,7 @@ auto DonsusParser::donsus_function_decl() -> parse_result { donsus_syntax_error(&declaration, cur_token.column, cur_token.line, "Return type received: '" + cur_token.value + "' in invalid for function: '" + - expression.func_name); + expression.func_name + "'"); parse_result tmp; return tmp; } From f817e5875b3a61b4dbc6353d5d4dc3369f275969 Mon Sep 17 00:00:00 2001 From: gaborhadhazy Date: Wed, 5 Jun 2024 17:02:51 +0100 Subject: [PATCH 12/16] donsus_function_def error --- src/parser.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/parser.cc b/src/parser.cc index 0dfc0d0..1954a89 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -1217,8 +1217,12 @@ auto DonsusParser::donsus_function_definition() -> parse_result { definition_expression.parameters = declaration_expression.parameters; definition_expression.return_type = declaration_expression.return_type; - donsus_parser_except_current(DONSUS_LBRACE); // expect cur_token to be "{" - definition_expression.body = donsus_statements(); + if (cur_token.kind == DONSUS_LBRACE) { + definition_expression.body = donsus_statements(); + } else { + donsus_parser_except_current(DONSUS_LBRACE); // expect cur_token to be "{" + } + return definition; } From ca8d8a184f9d30d621cfe18422fe5451c98474d6 Mon Sep 17 00:00:00 2001 From: gaborhadhazy Date: Wed, 5 Jun 2024 17:23:16 +0100 Subject: [PATCH 13/16] errors for if statement --- src/parser.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/parser.cc b/src/parser.cc index 1954a89..2887c4a 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -1232,7 +1232,7 @@ statements: |general_statement+ */ auto DonsusParser::donsus_statements() -> std::vector { std::vector body; - while (cur_token.kind != DONSUS_RBRACE) { + while (cur_token.kind != DONSUS_RBRACE && cur_token.kind != DONSUS_END) { /* general_statement: | func_def */ if (cur_token.kind == DONSUS_FUNCTION_DEFINITION_KW) { From 342a99660df2b51e470690ce3201027999853034 Mon Sep 17 00:00:00 2001 From: gaborhadhazy Date: Wed, 5 Jun 2024 18:06:10 +0100 Subject: [PATCH 14/16] array definition and return statement error --- src/parser.cc | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/parser.cc b/src/parser.cc index 2887c4a..2986396 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -784,11 +784,11 @@ auto DonsusParser::match_expressions(unsigned int ptp) -> parse_result { } default: { - // donsus_syntax_error(nullptr, cur_token.column, cur_token.line, - // "Invalid expression provided at token: " + - // cur_token.value); - // parse_result tmp; - // return tmp; + donsus_syntax_error(nullptr, cur_token.column, cur_token.line, + "Invalid expression provided at token: " + + cur_token.value); + parse_result tmp; + return tmp; } } } @@ -818,6 +818,10 @@ auto DonsusParser::donsus_expr(unsigned int ptp) -> parse_result { } else { left = match_expressions(ptp); if (!left) { + // throw error + donsus_syntax_error(nullptr, cur_token.column, cur_token.line, + "Invalid expression provided at token: " + + cur_token.value); parse_result tmp; return tmp; } @@ -1513,6 +1517,7 @@ auto DonsusParser::donsus_return_statement() -> parse_result { donsus_parser_next(); parse_result return_expression = donsus_expr(0); return_statement->children.push_back(return_expression); + donsus_parser_except(DONSUS_SEMICOLON); return return_statement; } From 9bd9b45b3010238f0c3ebfe1f17323b9554a5db7 Mon Sep 17 00:00:00 2001 From: gaborhadhazy Date: Wed, 5 Jun 2024 18:52:11 +0100 Subject: [PATCH 15/16] loop errors --- src/parser.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/parser.cc b/src/parser.cc index 2986396..6d05406 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -1370,8 +1370,7 @@ auto DonsusParser::donsus_while_loop() -> parse_result { auto &expression = while_loop->get(); - donsus_parser_next(); // move to the next token (condition for the while - // loop) + donsus_parser_except(DONSUS_LPAR); parse_result condition_expression = donsus_expr(0); while_loop->children.push_back(condition_expression); @@ -1379,6 +1378,7 @@ auto DonsusParser::donsus_while_loop() -> parse_result { donsus_parser_except_current(DONSUS_LBRACE); // expect cur_token to be "{" expression.body = donsus_statements(); + donsus_parser_except_current(DONSUS_RBRACE); // expect cur_token to be "{" return while_loop; } @@ -1416,6 +1416,7 @@ auto DonsusParser::donsus_range_for_loop(bool is_range_with_name) donsus_parser_except_current(DONSUS_LBRACE); // expect cur_token to be "{" expression.body = donsus_statements(); + donsus_parser_except_current(DONSUS_RBRACE); // expect cur_token to be "{" return range_for_loop; }; From 54aa36b47e8c042c1dd8e03818209cf6d20fdda0 Mon Sep 17 00:00:00 2001 From: gaborhadhazy Date: Sat, 8 Jun 2024 15:08:06 +0100 Subject: [PATCH 16/16] Language reference extended --- docs/source/glossary.rst | 12 +- docs/source/reference.rst | 529 +++++++++++++++++++++++++++++++++++++- 2 files changed, 529 insertions(+), 12 deletions(-) diff --git a/docs/source/glossary.rst b/docs/source/glossary.rst index dbc2bbb..309937d 100644 --- a/docs/source/glossary.rst +++ b/docs/source/glossary.rst @@ -222,12 +222,18 @@ a region of storage, so you can take its address:: Objects ~~~~~~~~~~~~ ---- - .. _types: Types -~~~~~~~~~~~~ +~~~~~~~~~ + +Donsus offers a various range of types for specific purposes depending on the context. Here are the accepted types:: + +- integer +- void +- bool +- float +- string implicit ~~~~~~~~~~~~ diff --git a/docs/source/reference.rst b/docs/source/reference.rst index c1dc3e6..69a4f8f 100644 --- a/docs/source/reference.rst +++ b/docs/source/reference.rst @@ -38,6 +38,83 @@ The following identifiers are used as reserved keywords of donsus, and cannot be return printf true false while for +These keywords are used to define the structure of the program and cannot be used as identifiers. +We are going to go through each of them in the following sections. + +.. _types_in_donsus: + +Types +~~~~~ +Donsus offers various types, the following are the types supported by donsus:: + +- integer +- void +- bool +- float +- string +- unary + +Here are the keywords used to represent these types in donsus:: + + int int8 int16 + int32 int64 u32 + u64 f32 f64 + bool void string + +Let's discuss each of them seperately. + +Integer types +------------- +Integers are used to represent whole numbers. In donsus there are multiple types of integers supported. The following are the integer types supported by donsus:: + + int int8 int16 + int32 int64 u32 + u64 + +- **int** is used to represent a 32 bit signed integer. +- **int8** is used to represent an 8 bit signed integer. +- **int16** type is used to represent a 16 bit signed integer. +- **int32** type is used to represent a 32 bit signed integer. +- **int64** type is used to represent a 64 bit signed integer. +- **u32** type is used to represent a 32 bit unsigned integer. +- **u64** type is used to represent a 64 bit unsigned integer. + +Float types +----------- +Floats are used to represent decimal numbers. In donsus there are multiple types of floats supported. The following are the float types supported by donsus:: + + f32 f64 + +- **f32** is used to represent a 32 bit float. +- **f64** is used to represent a 64 bit float. + +Boolean types +------------- + +Booleans are used to represent true or false values. In donsus there is only one type of boolean supported. The following is the boolean type supported by donsus:: + + bool + +- **bool** is used to represent a boolean value. It can either be true or false. + +String types +------------ + +Strings are used to represent text. In donsus there is only one type of string supported. The following is the string type supported by donsus:: + + string + +- **string** is used to represent a string value e.g "hello world". + +Void types +---------- + +Void is used to represent the absence of a value. In donsus there is only one type of void supported. The following is the void type supported by donsus:: + + void + +- **void** is used to represent the absence of a value e.g return type of a function is void if the function does not return a value. + .. _escaped-sequences: Escape sequences @@ -56,10 +133,41 @@ Literals are explicitly provided constant values assigned to variables. They represent fixed values that cannot be modified. There are multiple types of literal each of which corresponding to a **DONSUS_TYPE**:: - literal:string = "string_literal"; # string literal + literal:type = value; + +String literals +---------------- +String literals are sequences of characters enclosed in double quotes. They represent string data. +The following are examples of string literals:: + + a:string = "Hello World"; # string literal + + +Integer literals +---------------- +Integer literals are whole numbers without a decimal point. They represent integer data. +The following are examples of integer literals:: + a:int = 12; # int literal + b:u32 = 12; # u32 literal + +Float literals +-------------- +Float literals are numbers with a decimal point. They represent floating point data. +The following are examples of float literals:: + a:float = 12.1; # float literal +Boolean literals +---------------- +Boolean literals are either true or false. They represent boolean data. +The following are examples of boolean literals:: + + a:bool = true; # bool literal + +As of now Donsus doesn't support character literals and null literals. + + .. _operators: Operators @@ -77,16 +185,419 @@ These are the following operators in Donsus:: These include both binary and assignment operators. -Types -~~~~~~~~~ -Donsus offers a various range of types for specific purposes depending on the context. Here are the accepted types:: -- integer -- void -- bool -- float -- string + .. _arrays: + Arrays ~~~~~~ +Arrays are a collection of elements of the same type. In donsus there are three types of arrays supported: + + - static array(read only array with fixed size) + - dynamic array + - fixed sized array + +We are going to discuss each of them with examples. + + +Static Arrays +------------- + +In donsus, static arrays are read only arrays with fixed size. The size of the array is determined at compile time. The syntax for defining a static array is as follows:: + + a:int[5]. = [1,2,3,4,5]; + +It is very important to notice the dot after the size of the array. This is used to differentiate between **static** and **dynamic** arrays. +Static arrays are read only arrays. This means that you cannot change the size of the array or the elements of the array. Some other examples include:: + + b:float[5]. = [1.0,2.0,3.0,4.0,5.0]; + c:string[5]. = ["a","b","c","d","e"]; + d:bool[5]. = [true,false,true,false,true]; + +Dynamic Arrays +-------------- +Dynamic arrays are arrays whose size can be changed at runtime. Meaning you can add or remove elements from the array and the size does not need to be provided explicitly. The syntax for defining a dynamic array is as follows:: + + a:int[] = [1,2,3,4,5]; + +The above code declares a dynamic array of integers with 5 elements. Some other examples include:: + + b:float[] = [1.0,2.0,3.0,4.0,5.0]; + c:string[] = ["a","b","c","d","e"]; + d:bool[] = [true,false,true,false,true]; + +Fixed Sized Arrays +------------------ +Fixed sized arrays are arrays whose size is determined at runtime but cannot be changed. Unlike static arrays elements of fixed sized arrays can be changed only the size cannot. The syntax for defining a fixed sized array is as follows:: + + a:int[5] = [1,2,3,4,5]; + +The above code declares a fixed sized array of integers with 5 elements. It is important to notice that there is no dot after the size of the array. Some other examples include:: + + b:float[5] = [1.0,2.0,3.0,4.0,5.0]; + c:string[5] = ["a","b","c","d","e"]; + d:bool[5] = [true,false,true,false,true]; + +.. _functions_in_donsus: + +Functions +~~~~~~~~~ + +Functions are a block of code that performs a specific task that are used to break down the code into smaller and modular pieces. In donsus functions are defined using the keyword **def** followed by the function name and the parameters in parentheses. The syntax for defining a function is as follows:: + + def function_name(parameter1:DONSUS_TYPE,parameter2:DONSUS_TYPE,...) -> DONSUS_TYPE { + # code block + } + + def function_name_declare(parameter1:DONSUS_TYPE,parameter2:DONSUS_TYPE,...) -> DONSUS_TYPE; + +The return type of the function is specified after the arrow **->** and the types for the parameters have to be seperated by a colo(aka **DONSUS_COLO**). Accepted return types are: :ref:`types`. The function can return a value of the specified type. If the function does not return a value the **void** return type should be used. The function can be called by using the function name followed by the parameters in parentheses. The syntax for calling a function is as follows:: + + function_name(argument1,argument2,...); + +Both the arguments and the parameters are seperated by commas. +As of now donsus doesn't support function overloading however it supports nested functions. This means that you cannot have two functions with the same name but different parameters in donsus. + + +In regards of the function's body, donsus supports the following statements:: + + - if + - elif + - else + - while + - for + - return + - printf + +We are going to talk about all of them in the following sections. + +Some examples for the usage of functions in donsus are as follows:: + + def add(a:int,b:int) -> int { + return a+b; + } + + def nested_function() -> void { + def nested_function2() -> void { + printf("This is a nested function"); + } + nested_function2(); + } + + def if_else(a:int) -> void { + if(a>0) { + printf("a is greater than 0"); + } elif (a==0) { + printf("a is less than or equal to 0"); + } else { + printf("a is less than 0"); + } + } + + def while_loop(a:int) -> void { + while(a>0) { + printf("a is greater than 0"); + a = a - 1; + } + } + + def for_loop(a:int) -> void { + for number: 2..10 { + printf(number); + } + } + +.. _compound_statements_in_donsus: + +Simple and Compound Statements +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If-elif-else Statements +----------------------- +In general the if-elif-else statement is used to make decisions in the code. The syntax for the if-elif-else statement is as follows:: + + if(DONSUS_EXPRESSION) { + # code block + } elif(DONSUS_EXPRESSION) { + # code block + } else { + # code block + } + +**DONSUS_EXPRESSION** is a combination of operands and operators within donsus. This is a core element of donsus which is out of the context of this reference, however here it is a placeholder for a boolean expression. +The condition has to be provided in parentheses. The body of the if-elif-else statement accepts the same statements as the function body. + +The code block is executed if the expression evaluates to true. If the expression evaluates to false the code block is skipped. The elif and else blocks are optional. The elif block is executed if the if block evaluates to false and the elif expression evaluates to true. The else block is executed if the if and elif blocks evaluate to false. + + +Some examples for the usage of if-elif-else statements in donsus are as follows:: + + def if_else(a:int) -> void { + if(a>0) { + printf("a is greater than 0"); + } elif (a==0) { + printf("a is less than or equal to 0"); + } else { + printf("a is less than 0"); + } + } + + if_else(5); # prints "a is greater than 0" + if_else(0); # prints "a is less than or equal to 0" + if_else(-5); # prints "a is less than 0" + +.. _while: + +While Loops +----------- +The while loop is used to execute a block of code repeatedly as long as the condition specified in the loop is true. The syntax for the while loop is as follows:: + + while(DONSUS_EXPRESSION) { + # code block + } + +**DONSUS_EXPRESSION** Appears in the same context as in the if-elif-else statement. The code block is executed as long as the expression evaluates to true. If the expression evaluates to false the loop is exited and the code block is skipped. +The condition has to be provided in parentheses. The body of the while loop accepts the same statements as the function body. + +Some examples for the usage of while loops in donsus are as follows:: + + def while_loop(a:int) -> void { + while(a>0) { + printf("a is greater than 0"); + a = a - 1; + } + } + + while_loop(5); # prints "a is greater than 0" 5 times + +.. _for: + +For Loops +--------- +The for loop is used to execute a block of code repeatedly. In donsus there are two types of for loops. The first type is the for loop that iterates over a range of numbers. The second type is the for loop that iterates over an array. + +Let's discuss each of them seperately. + +For Loops Over a Range of Numbers +================================== + +The syntax for the for loop that iterates over a range of numbers is as follows:: + + for variable: start..end { + # code block + } + +First of all after the **for** keyword the variable that is used to iterate over the range of numbers **can** be provided, if it is not provided donsus will set the variable **it** as default. The range of numbers is specified by the **start** and **end** values seperated by two dots. + +Both the **start** and **end** values have to be integers. The code block is executed for each number in the range of numbers. + +The body of the for loop accepts the same statements as the function body. + +Some examples for the usage of for loops over a range of numbers in donsus are as follows:: + + def for_loop(a:int) -> void { + for number: 2..10 { + printf(number); + } + } + + for_loop(5); # prints 2 3 4 5 6 7 8 9 10 + +For Loops Over an Array +======================== +The syntax for the for loop that iterates over an array is as follows:: + + for variable: array { + # code block + } + +First of all after the **for** keyword the variable that is used to iterate over the array **can** be provided, if it is not provided donsus will set the variable **it** as default. The array is specified by the **array** value which has to refer to a valid array. + +The code block is executed for each element in the array. + +The body of the for loop accepts the same statements as the function body. + +Some examples for the usage of for loops over an array in donsus are as follows:: + + def for_loop_array() -> void { + a:int[] = [1,2,3,4,5]; + for number: a { + printf(number); + } + } + + for_loop_array(); # prints 1 2 3 4 5 + +.. _return: + +Return Statement +---------------- +The return statement is used to return a value from a function. The syntax for the return statement is as follows:: + + return DONSUS_EXPRESSION; + +**DONSUS_EXPRESSION** Appears in the same context as in the if-elif-else statement. The return statement is used to return a value from a function. The return type of the function has to match the type of the expression. If the return statement is not provided the function have return **void**. +There must be a semicolon at the end of the return statement. + +Some examples for the usage of return statements in donsus are as follows:: + + def add(a:int,b:int) -> int { + return a+b; + } + + def subtract(a:int,b:int) -> int { + return a-b; + } + + def multiply(a:int,b:int) -> int { + return a*b; + } + + def divide(a:int,b:int) -> int { + return a/b; + } + +.. _printf: + +Printf Statement +---------------- +The printf statement is used to print a value to the terminal. The syntax for the printf statement is as follows:: + + printf(DONSUS_EXPRESSION); + +**DONSUS_EXPRESSION** Appears in the same context as in the if-elif-else statement. The printf statement is used to print a value to the terminal. The value can be a anything within the boundaries of a donsus expression. + +Some examples for the usage of printf statements in donsus are as follows:: + + def print_hello_world() -> void { + printf("Hello World"); + } + + def print_number(a:int) -> void { + printf(a); + } + + def print_float(a:float) -> void { + printf(a); + } + + def print_string(a:string) -> void { + printf(a); + } + + def print_bool(a:bool) -> void { + printf(a); + } + + + +.. _expressions_in_donsus: + +Expressions +~~~~~~~~~~~ + +Expressions are the building blocks of donsus. They are used to perform operations on variables and values. There are multiple types of expressions in donsus, they all have the type **DONSUS_EXPRESSION**. +We are going to talk about the presence of expressions in donsus and what are the accepted types of expressions. + +Number Expressions +------------------ + +Number expressions are used to perform operations on numbers. The following operators are supported for number expressions and any combination of expressions in general:: + + + += - + -= * *= + / /= > + >= < <= + == != + +This list also includes comparison operators. The comparison operators are used to compare two expressions. The comparison operators return a boolean value and can be used in statements:: + + > >= < <= + == != + +Donsus also supports **float expressions** and **unary expressions**. Some examples for the usage of number expressions in donsus are as follows:: + + def add(a:int,b:int) -> int { + return a+b; + } + + def subtract(a:int,b:int) -> int { + return a-b; + } + + def multiply(a:int,b:int) -> int { + return a*b; + } + + def divide(a:int,b:int) -> int { + return a/b; + } + + def compare(a:int,b:int) -> bool { + return a>b; + } + + def compare_float(a:float,b:float) -> bool { + return a>b; + } + + def unary(a:int) -> int { + return -a; + } + + def unary_float(a:float) -> float { + return -a; + } + +String Expressions +------------------ + +String expressions are used to perform operations on strings. In donsus here is how to define a string expression:: + + a:string = "Hello"; + b:string = "World"; + c:string = a+b; + +It's important to note that the operators mentioned before apply to all expressions and the combination of expressions as long as they used correctly. +Some examples for the usage of string expressions in donsus are as follows:: + + def concat(a:string,b:string) -> string { + return a+b; + } + + def compare_string(a:string,b:string) -> bool { + return a==b; + } + + def compare_string_not_equal(a:string,b:string) -> bool { + return a!=b; + } + +Boolean Expressions +------------------- + +In donsus a bool expression can either be **true** or **false**. These are keywords in donsus specifically reserved for boolean expressions. +Boolean expressions must be used with the **bool** type. Here is how to use them in donsus:: + + a:bool = true; + b:bool = false; + + +Operator precedence in Expressions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The following table lists the precedence of operators in donsus, from highest to lowest. Operators in the same box have the same precedence. + +.. list-table:: Title + :widths: 100 100 + :header-rows: 1 + + * - Operators + - Precedence + * - **>=**, **>**, **<=**, **<**, **!=**, **==** + - 1 + * - **+**, **-** + - 10 + * - * , **/** + - 20