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