From 983f36e37e4069790f42270a8d2ddd9c7380f5eb Mon Sep 17 00:00:00 2001 From: Peter Matta <mattapet@fit.cvut.cz> Date: Sun, 6 May 2018 14:58:57 +0200 Subject: [PATCH] Rewritten example tests --- examples/factRec.dusk | 16 +++++ examples/factor.dusk | 39 ++++++++++++ examples/fibonacci.dusk | 15 +++++ examples/funcDecl.dusk | 14 ++--- examples/gcd.dusk | 37 ++++++++++++ examples/globExpr.dusk | 20 ++----- examples/inOut.dusk | 22 +++++++ examples/interpRec.dusk | 23 +++++++ examples/isPrime.dusk | 119 +++++++++++++++++++++++++++++++++++++ include/dusk/AST/Type.h | 14 ++--- lib/IRGen/GenFunc.cpp | 48 ++++++++++++++- lib/IRGen/IRGenFunc.cpp | 4 +- lib/IRGen/IRGenModule.cpp | 16 +++-- lib/Parser/Lexer.cpp | 2 +- lib/Parser/ParseExpr.cpp | 2 +- lib/Sema/TypeCheckStmt.cpp | 2 +- test.cpp | 20 +++++-- 17 files changed, 367 insertions(+), 46 deletions(-) create mode 100644 examples/factRec.dusk create mode 100644 examples/factor.dusk create mode 100644 examples/fibonacci.dusk create mode 100644 examples/gcd.dusk create mode 100644 examples/inOut.dusk create mode 100644 examples/interpRec.dusk create mode 100644 examples/isPrime.dusk diff --git a/examples/factRec.dusk b/examples/factRec.dusk new file mode 100644 index 0000000..3333913 --- /dev/null +++ b/examples/factRec.dusk @@ -0,0 +1,16 @@ +extern func println(int: Int) -> Void; +extern func readln() -> Int; + + +func fact(n: Int) -> Int { + if n == 0 { + return 1; + } else { + return n * fact(n - 1); + } +} + +func main_() { + let n = readln(); + println(fact(n)); +} diff --git a/examples/factor.dusk b/examples/factor.dusk new file mode 100644 index 0000000..67dce84 --- /dev/null +++ b/examples/factor.dusk @@ -0,0 +1,39 @@ +extern func println(int: Int) -> Void; +extern func readln() -> Int; + +func factorize(n: Int, fact: Int) -> Int { + var ret = n; + while ret % fact == 0 { + println(fact); + ret = ret / fact; + } + return ret; +} + +func factorization(n: Int) { + var ret = n; + if n < 4 { + println(4); + return; + } + + ret = factorize(ret, 2); + ret = factorize(ret, 3); + + let max = ret; + var i = 5; + while i <= max { + ret = factorize(ret, i); + i = i + 2; + ret = factorize(ret, i); + i = i + 4; + } + if ret != 1 { + println(ret); + } +} + +func main_() { + let n = readln(); + factorization(n); +} diff --git a/examples/fibonacci.dusk b/examples/fibonacci.dusk new file mode 100644 index 0000000..3dd6c3c --- /dev/null +++ b/examples/fibonacci.dusk @@ -0,0 +1,15 @@ +extern func println(int: Int) -> Void; +extern func readln() -> Int; + +func fib(n: Int) -> Int { + if n < 2 { + return n; + } else { + return fib(n - 1) + fib(n - 2); + } +} + +func main_() { + let n = readln(); + println(fib(n)); +} diff --git a/examples/funcDecl.dusk b/examples/funcDecl.dusk index 2b13d55..908c46e 100644 --- a/examples/funcDecl.dusk +++ b/examples/funcDecl.dusk @@ -1,22 +1,20 @@ //extern func test(); -extern func println(output: Int) -> Int; +extern func println(output: Int) -> Void; +extern func readln() -> Int; /*func main(arg1: Int) -> Int { return arg1; }*/ -func isEven(val: Int) { - var i = 0; - while 1 { +func isEven(val: Int) -> Int { + for i in 0..val { println(i); - i = i + 1; - if i > val { - break; - } } + return 0; } func inc(i: Int) -> Int { println(i); return i + 1; } + diff --git a/examples/gcd.dusk b/examples/gcd.dusk new file mode 100644 index 0000000..42383f4 --- /dev/null +++ b/examples/gcd.dusk @@ -0,0 +1,37 @@ +extern func println(int: Int) -> Void; +extern func readln() -> Int; + +func gcdi(a: Int, b: Int) -> Int { + while b != 0 { + let tmp = b; + b = a % b; + a = tmp; + } + return a; +} + +func gcdr(a: Int, b: Int) -> Int { + let tmp = a % b; + if tmp == 0 { + return b; + } else { + return gcdr(b, tmp); + } +} + +func gcdrGuessingInner(a: Int, b: Int, c: Int) -> Int { + if a % c == 0 && b % c == 0 { + return c; + } + return gcdrGuessingInner(a, b, c - 1); +} + +func gcdrGuessing(a: Int, b: Int) -> Int { + return gcdrGuessingInner(a, b, b); +} + +func main_() { + println(gcdi(27*2, 27*3)); + println(gcdr(27*2, 27*3)); + println(gcdrGuessing(27*2, 27*3)); +} diff --git a/examples/globExpr.dusk b/examples/globExpr.dusk index 49a1776..8c1acd7 100644 --- a/examples/globExpr.dusk +++ b/examples/globExpr.dusk @@ -1,17 +1,7 @@ -extern func ext(a: Int) -> Void; +extern func println(val: Int) -> Void; +extern func readln() -> Int; -var a: Int; -a = 14; -let d: Int = a + 99; -a = (1 + 2) * 8 == 2; -a = (1 + 2 * d) || (4 % 3); -ext(d); - -// var v = ext(a); -// var vv; -// var vvv: Int; -// let l: Int = 4; -// let ll = 44; -// let lll: Int; -ll = 14; +func main_() { + println(0x10); +} diff --git a/examples/inOut.dusk b/examples/inOut.dusk new file mode 100644 index 0000000..9afe30f --- /dev/null +++ b/examples/inOut.dusk @@ -0,0 +1,22 @@ +extern func println(int: Int) -> Void; +extern func readln() -> Int; + +var n: Int; + +func main_() { + n = readln(); + println(n); +} + + +/* +program inputOutput; + +var + n: integer; + +begin + readln(n); + writeln(n); +end. +*/ diff --git a/examples/interpRec.dusk b/examples/interpRec.dusk new file mode 100644 index 0000000..140066d --- /dev/null +++ b/examples/interpRec.dusk @@ -0,0 +1,23 @@ +extern func println(int: Int) -> Void; +extern func readln() -> Int; + +func isOdd(n: Int) -> Int { + if n > 0 { + return isEven(n - 1); + } + return 0; +} + +func isEven(n: Int) -> Int { + if n > 0 { + return isOdd(n - 1); + } + return 1; +} + +func main_() { + let n = readln(); + println(isEven(n)); + println(isOdd(n)); +} + diff --git a/examples/isPrime.dusk b/examples/isPrime.dusk new file mode 100644 index 0000000..1d876ae --- /dev/null +++ b/examples/isPrime.dusk @@ -0,0 +1,119 @@ +extern func println(int: Int) -> Void; +extern func readln() -> Int; + +func isPrime(n: Int) -> Int { + if n < 2 { + return 0; + } + if n < 4 { + return 1; + } + if n % 2 == 0 || n % 3 == 0 { + return 0; + } + + let max = n; + var i = 5; + while 1 { + if i >= max { + return 1; + } + if n % i == 0 { + return 0; + } + + i = i + 2; + if i >= max { + return 1; + } + if n % i == 0 { + return 0; + } + i = i + 4; + } +} + +func main_() { + // println(0); + // println(isPrime(0)); + // println(1); + // println(isPrime(1)); + // println(2); + // println(isPrime(2)); + // println(3); + // println(isPrime(3)); + // println(4); + // println(isPrime(4)); + // println(5); + // println(isPrime(5)); + // println(6); + // println(isPrime(6)); + // println(7); + // println(isPrime(7)); + // println(8); + // println(isPrime(8)); + // println(9); + // println(isPrime(9)); + // println(10); + // println(isPrime(10)); + println(11); + println(isPrime(11)); + println(12); + println(isPrime(12)); + println(13); + println(isPrime(13)); + println(14); + println(isPrime(14)); + println(15); + println(isPrime(15)); + println(16); + println(isPrime(16)); + println(17); + println(isPrime(17)); + +} + +/* +program isprime; + +function isprime(n: integer): integer; +var max, i: integer; +begin + if n < 2 then + begin + isprime := 0; + exit; + end; + if n < 4 then + begin + isprime := 1; + exit + end; + if ((n mod 2) = 0) or ((n mod 3) = 0) then + begin + isprime := 0; + exit + end; + + isprime := 1; + max := n; + i := 5; + while i < max do + begin + if( i > max ) then exit; + if ((n mod i) = 0) then + begin + isprime := 0; + exit; + end; + i := i + 2; + if ( i < max ) then exit; + if ((n mod i) = 0) then + begin + isprime := 0; + exit; + end; + i := i + 4; + end; +end; +*/ diff --git a/include/dusk/AST/Type.h b/include/dusk/AST/Type.h index 785e67c..c80ce02 100644 --- a/include/dusk/AST/Type.h +++ b/include/dusk/AST/Type.h @@ -53,8 +53,8 @@ public: class VoidType : public Type { public: VoidType(); - virtual bool isVoidType() const override { return false; } - virtual bool isClassOf(const Type *T) const override { + bool isVoidType() const override { return true; } + bool isClassOf(const Type *T) const override { return dynamic_cast<const VoidType *>(T) != nullptr; } }; @@ -63,7 +63,7 @@ public: class IntType : public ValueType { public: IntType(); - virtual bool isClassOf(const Type *T) const override { + bool isClassOf(const Type *T) const override { return dynamic_cast<const IntType *>(T) != nullptr; } }; @@ -77,13 +77,13 @@ public: Type *getArgsType() const { return ArgsTy; } Type *getRetType() const { return RetTy; } - virtual bool isClassOf(const Type *T) const override { + bool isClassOf(const Type *T) const override { if (auto Ty = dynamic_cast<const FunctionType *>(T)) return isClassOf(Ty); return false; } - virtual bool isClassOf(const FunctionType *T) const; + bool isClassOf(const FunctionType *T) const; }; class PatternType : public Type { @@ -94,12 +94,12 @@ public: ArrayRef<Type *> getItems() const { return Items; } - virtual bool isClassOf(const Type *T) const override { + bool isClassOf(const Type *T) const override { if (auto Ty = dynamic_cast<const PatternType *>(T)) return isClassOf(Ty); return false; } - virtual bool isClassOf(const PatternType *T) const; + bool isClassOf(const PatternType *T) const; }; } // namespace dusk diff --git a/lib/IRGen/GenFunc.cpp b/lib/IRGen/GenFunc.cpp index fb11e1b..a2e7d36 100644 --- a/lib/IRGen/GenFunc.cpp +++ b/lib/IRGen/GenFunc.cpp @@ -153,7 +153,53 @@ public: return true; } - bool visit(ForStmt *S) { return true; } + bool visit(ForStmt *S) { + // Create loop blocks + auto HeaderBlock = + llvm::BasicBlock::Create(IRGF.IRGM.LLVMContext, "loop.header", IRGF.Fn); + auto BodyBlock = + llvm::BasicBlock::Create(IRGF.IRGM.LLVMContext, "loop.body"); + auto EndBlock = llvm::BasicBlock::Create(IRGF.IRGM.LLVMContext, "loop.end"); + IRGF.IRGM.Lookup.push(); + IRGF.LoopStack.push(HeaderBlock, EndBlock); + + // Add block to function. + IRGF.Fn->getBasicBlockList().push_back(BodyBlock); + IRGF.Fn->getBasicBlockList().push_back(EndBlock); + + // Emit initialization + auto Iter = IRGF.declare(S->getIter()); + auto Rng = static_cast<RangeStmt *>(S->getRange()); + auto Val = codegenExpr(IRGF.IRGM, Rng->getStart()); + IRGF.Builder.CreateStore(Val, Iter); + IRGF.Builder.CreateBr(HeaderBlock); + + // Emit condition + IRGF.Builder.SetInsertPoint(HeaderBlock); + auto LHS = IRGF.Builder.CreateLoad(Iter); + auto RHS = codegenExpr(IRGF.IRGM, Rng->getEnd()); + auto Cond = IRGF.Builder.CreateICmpNE(LHS, RHS); + IRGF.Builder.CreateCondBr(Cond, BodyBlock, EndBlock); + + // Emit loop body + IRGF.Builder.SetInsertPoint(BodyBlock); + if (!super::visit(S->getBody())) + return false; + // Jump back to the condition + auto Ty = llvm::Type::getInt64Ty(IRGF.IRGM.LLVMContext); + auto IV = llvm::ConstantInt::get(Ty, 1); + auto Incr = IRGF.Builder.CreateAdd(IRGF.Builder.CreateLoad(Iter), IV); + IRGF.Builder.CreateStore(Incr, Iter); + if (IRGF.Builder.GetInsertBlock()->getTerminator() == nullptr) + IRGF.Builder.CreateBr(HeaderBlock); + + IRGF.Builder.SetInsertPoint(EndBlock); + IRGF.LoopStack.pop(); + IRGF.IRGM.Lookup.pop(); + return true; + } + + bool visit(FuncStmt *S) { return true; } bool visit(RangeStmt *S) { return true; } bool visit(SubscriptStmt *S) { return true; } diff --git a/lib/IRGen/IRGenFunc.cpp b/lib/IRGen/IRGenFunc.cpp index feb43e9..139cc2b 100644 --- a/lib/IRGen/IRGenFunc.cpp +++ b/lib/IRGen/IRGenFunc.cpp @@ -56,7 +56,7 @@ void IRGenFunc::emitHeader() { unsigned idx = 0; auto Args = Proto->getArgs()->getVars(); for (auto &Arg : Fn->args()) { - if (auto Addr = declare(Args[idx])) + if (auto Addr = declare(Args[idx++])) Builder.CreateStore(&Arg, Addr); else llvm_unreachable("Redefinition of declaration"); @@ -66,7 +66,7 @@ void IRGenFunc::emitHeader() { void IRGenFunc::emitRet() { for (auto &BB : Fn->getBasicBlockList()) { - if (BB.size() == 0) { + if (BB.getTerminator() == nullptr) { Builder.SetInsertPoint(&BB); if (auto Succ = BB.getSingleSuccessor()) Builder.CreateBr(Succ); diff --git a/lib/IRGen/IRGenModule.cpp b/lib/IRGen/IRGenModule.cpp index 8de023c..32d10d1 100644 --- a/lib/IRGen/IRGenModule.cpp +++ b/lib/IRGen/IRGenModule.cpp @@ -12,6 +12,7 @@ #include "dusk/AST/Decl.h" #include "dusk/AST/Type.h" #include "dusk/AST/ASTContext.h" +#include "llvm/ADT/APSInt.h" #include "llvm/IR/Type.h" #include "llvm/IR/Module.h" #include "llvm/IR/Function.h" @@ -30,12 +31,19 @@ Address IRGenModule::declareVal(Decl *D) { auto Ty = llvm::Type::getInt64Ty(LLVMContext); if (Lookup.getDepth() == 0) { - if (Module->getGlobalVariable(D->getName()) != nullptr) + if (!Lookup.declareVar(D)) llvm_unreachable("Redefinition of a variable"); - return Module->getOrInsertGlobal(D->getName(), Ty); + auto Ty = llvm::Type::getInt64Ty(LLVMContext); + + auto gvar = new llvm::GlobalVariable(*Module, Ty, false, + llvm::GlobalValue::InternalLinkage, + nullptr, D->getName()); + gvar->setInitializer(llvm::ConstantInt::get(Ty, 0)); + return gvar; } else { - Lookup.declareVar(D); + if (!Lookup.declareVar(D)) + llvm_unreachable("Redefinition of a variable"); auto Addr = Builder.CreateAlloca(Ty); Vals[D] = Addr; return Addr; @@ -72,7 +80,7 @@ Address IRGenModule::declareFunc(FuncDecl *D) { Address IRGenModule::getVal(StringRef N) { if (auto Val = Vals[Lookup.getVal(N)]) return Val; - return Module->getGlobalVariable(N); + return Module->getGlobalVariable(N, true); } llvm::Function *IRGenModule::getFunc(StringRef N) { diff --git a/lib/Parser/Lexer.cpp b/lib/Parser/Lexer.cpp index 05d0873..e620c53 100644 --- a/lib/Parser/Lexer.cpp +++ b/lib/Parser/Lexer.cpp @@ -539,7 +539,7 @@ void Lexer::lexBinNumber() { const char *TokEnd = CurPtr; CurPtr = TokStart + 2; // skip `0b` prefix - // Consume only valid [0-7] character. + // Consume only valid (0|1) character. while (consumeIfValidBinDigit(CurPtr)); // Validate number of consumed characters. diff --git a/lib/Parser/ParseExpr.cpp b/lib/Parser/ParseExpr.cpp index 5e274be..b8f9627 100644 --- a/lib/Parser/ParseExpr.cpp +++ b/lib/Parser/ParseExpr.cpp @@ -153,7 +153,7 @@ Expr *Parser::parseNumberLiteralExpr() { auto R = Tok.getRange(); int64_t Value; if (Str.size() > 1) { - llvm::StringRef B = Str.slice(2, Str.size() - 1); + llvm::StringRef B = Str.slice(2, Str.size()); // Parse hexadecimal literal if (Str[0] == '0' && Str[1] == 'x') diff --git a/lib/Sema/TypeCheckStmt.cpp b/lib/Sema/TypeCheckStmt.cpp index 37afede..048432b 100644 --- a/lib/Sema/TypeCheckStmt.cpp +++ b/lib/Sema/TypeCheckStmt.cpp @@ -22,7 +22,7 @@ bool TypeChecker::preWalkBlockStmt(BlockStmt *S) { auto Proto = static_cast<FuncDecl *>(Fn->getPrototype()); auto Args = static_cast<VarPattern *>(Proto->getArgs()); for (auto Arg : Args->getVars()) - if (!DeclCtx.declareLet(Arg)) { + if (!DeclCtx.declareVar(Arg)) { diagnose(Args->getLocStart(), diag::redefinition_of_identifier); return false; } diff --git a/test.cpp b/test.cpp index b28d983..8eb1866 100644 --- a/test.cpp +++ b/test.cpp @@ -2,7 +2,8 @@ extern "C" { int64_t inc(int64_t); - void isEven(int64_t); + int64_t isEven(int64_t); + void main_(); } #ifdef _WIN32 @@ -13,18 +14,25 @@ extern "C" { /// printd - printf that takes an integer prints it as "%lld\n", returning Void. extern "C" DLLEXPORT void println(int64_t X) { - std::cout << "being called externally " << X << std::endl; -// fprintf(stderr, "%lld\n", X); + fprintf(stdout, "%lld\n", X); return; } +/// printd - printf that takes an integer prints it as "%lld\n", returning Void. +extern "C" DLLEXPORT int64_t readln() { + int64_t X; + fscanf(stdin, "%lld", &X); + return X; +} + int main() { int64_t i = 10000; int64_t j = 5; // std::cout << i << " " << inc(i) << std::endl; // isEven(i); - isEven(j); - // std::cout << i << " is even "; isEven(i); std::cout << std::endl; - // std::cout << j << " is even "; isEven(j); std::cout << std::endl; + // std::cout << i << " is even " << isEven(i) << std::endl; + // std::cout << j << " is even " << isEven(j) << std::endl; + // isEven(j); + main_(); return 0; } -- GitLab