// examples/loops translated by mycpp

// BEGIN mycpp output

#include "mycpp/runtime.h"

GLOBAL_STR(str0, "--- list comprehension");
GLOBAL_STR(str1, "len = %d");
GLOBAL_STR(str2, "y[0] = %d");
GLOBAL_STR(str3, "y[-1] = %d");
GLOBAL_STR(str4, "--- list comprehension changing type");
GLOBAL_STR(str5, "[%d]");
GLOBAL_STR(str6, "len = %d");
GLOBAL_STR(str7, "z[0] = %s");
GLOBAL_STR(str8, "z[-1] = %s");
GLOBAL_STR(str9, "one");
GLOBAL_STR(str10, "two");
GLOBAL_STR(str11, "first = %s");
GLOBAL_STR(str12, "a");
GLOBAL_STR(str13, "b");
GLOBAL_STR(str14, "");
GLOBAL_STR(str15, "-");
GLOBAL_STR(str16, "");
GLOBAL_STR(str17, "--- Dict");
GLOBAL_STR(str18, "a");
GLOBAL_STR(str19, "c");
GLOBAL_STR(str20, "b");
GLOBAL_STR(str21, "a = %d");
GLOBAL_STR(str22, "a");
GLOBAL_STR(str23, "b = %d");
GLOBAL_STR(str24, "b");
GLOBAL_STR(str25, "c = %d");
GLOBAL_STR(str26, "c");
GLOBAL_STR(str27, "k = %s");
GLOBAL_STR(str28, "k = %s, v = %d");
GLOBAL_STR(str29, "big");
GLOBAL_STR(str30, "small");
GLOBAL_STR(str31, "hairless");
GLOBAL_STR(str32, "--- iterate over bytes in string");
GLOBAL_STR(str33, "abc");
GLOBAL_STR(str34, "ch = %s");
GLOBAL_STR(str35, "--- iterate over items in list");
GLOBAL_STR(str36, "xx");
GLOBAL_STR(str37, "yy");
GLOBAL_STR(str38, "item = %s");
GLOBAL_STR(str39, "--- tuple unpacking");
GLOBAL_STR(str40, "five");
GLOBAL_STR(str41, "six");
GLOBAL_STR(str42, "- [%d] %s");
GLOBAL_STR(str43, "--- one arg xrange()");
GLOBAL_STR(str44, "%d");
GLOBAL_STR(str45, "--- two arg xrange()");
GLOBAL_STR(str46, "%d");
GLOBAL_STR(str47, "--- three arg xrange()");
GLOBAL_STR(str48, "%d");
GLOBAL_STR(str49, "--- three arg reverse xrange()");
GLOBAL_STR(str50, "reverse %d");
GLOBAL_STR(str51, "--- enumerate()");
GLOBAL_STR(str52, "%d %s");
GLOBAL_STR(str53, "%d %d %s");
GLOBAL_STR(str54, "--- reversed() list");
GLOBAL_STR(str55, "spam");
GLOBAL_STR(str56, "eggs");
GLOBAL_STR(str57, "- %s");
GLOBAL_STR(str58, "--- reversed() list with tuple unpacking");
GLOBAL_STR(str59, "- [%d] %s");
GLOBAL_STR(str60, "result = %d");
GLOBAL_STR(str61, "Ran %d iterations of xrange/enumerate");

namespace loops {  // forward declare


}  // forward declare namespace loops

namespace loops {  // declare

void TestListComp();
void TestDict();
extern List<BigStr*>* CATS;
void run_tests();
void run_benchmarks();

}  // declare namespace loops

namespace loops {  // define


void TestListComp() {
  List<int>* x = nullptr;
  List<int>* y = nullptr;
  List<BigStr*>* z = nullptr;
  List<Tuple2<BigStr*, int>*>* pairs = nullptr;
  List<BigStr*>* first = nullptr;
  BigStr* s = nullptr;
  List<BigStr*>* parts = nullptr;
  List<BigStr*>* tmp = nullptr;
  List<BigStr*>* tmp2 = nullptr;
  StackRoot _root0(&x);
  StackRoot _root1(&y);
  StackRoot _root2(&z);
  StackRoot _root3(&pairs);
  StackRoot _root4(&first);
  StackRoot _root5(&s);
  StackRoot _root6(&parts);
  StackRoot _root7(&tmp);
  StackRoot _root8(&tmp2);

  mylib::print_stderr(str0);
  x = NewList<int>(std::initializer_list<int>{1, 2, 3, 4});
  y = Alloc<List<int>>();
  for (ListIter<int> it(x->slice(1)); !it.Done(); it.Next()) {
    int i = it.Value();
    y->append((i * 5));
  }
  mylib::print_stderr(StrFormat("len = %d", len(y)));
  mylib::print_stderr(StrFormat("y[0] = %d", y->at(0)));
  mylib::print_stderr(StrFormat("y[-1] = %d", y->at(-1)));
  mylib::print_stderr(str4);
  z = Alloc<List<BigStr*>>();
  for (ListIter<int> it(x->slice(1, -1)); !it.Done(); it.Next()) {
    int i = it.Value();
    z->append(StrFormat("[%d]", i));
  }
  mylib::print_stderr(StrFormat("len = %d", len(z)));
  mylib::print_stderr(StrFormat("z[0] = %s", z->at(0)));
  mylib::print_stderr(StrFormat("z[-1] = %s", z->at(-1)));
  pairs = NewList<Tuple2<BigStr*, int>*>(std::initializer_list<Tuple2<BigStr*, int>*>{(Alloc<Tuple2<BigStr*, int>>(str9, 1)), (Alloc<Tuple2<BigStr*, int>>(str10, 2))});
  first = Alloc<List<BigStr*>>();
  for (ListIter<Tuple2<BigStr*, int>*> it(pairs); !it.Done(); it.Next()) {
    Tuple2<BigStr*, int>* tup0 = it.Value();
    s = tup0->at0();
    first->append(s);
  }
  for (ListIter<BigStr*> it(first); !it.Done(); it.Next()) {
    BigStr* s2 = it.Value();
    StackRoot _for(&s2  );
    mylib::print_stderr(StrFormat("first = %s", s2));
  }
  parts = NewList<BigStr*>(std::initializer_list<BigStr*>{str12, nullptr, str13});
  tmp = Alloc<List<BigStr*>>();
  for (ListIter<BigStr*> it(parts); !it.Done(); it.Next()) {
    BigStr* s = it.Value();
    if (s != nullptr) {
      tmp->append(s);
    }
  }
  print(str14->join(tmp));
  tmp2 = Alloc<List<BigStr*>>();
  for (ListIter<BigStr*> it(tmp); !it.Done(); it.Next()) {
    BigStr* s = it.Value();
    if (s->startswith(str15)) {
      tmp2->append(s);
    }
  }
  print(str16->join(tmp2));
}

void TestDict() {
  Dict<BigStr*, int>* d = nullptr;
  StackRoot _root0(&d);

  mylib::print_stderr(str17);
  d = Alloc<Dict<BigStr*, int>>();
  d->set(str18, 99);
  d->set(str19, 42);
  d->set(str20, 0);
  mylib::print_stderr(StrFormat("a = %d", d->at(str22)));
  mylib::print_stderr(StrFormat("b = %d", d->at(str24)));
  mylib::print_stderr(StrFormat("c = %d", d->at(str26)));
  for (DictIter<BigStr*, int> it(d); !it.Done(); it.Next()) {
    BigStr* k = it.Key();
    StackRoot _for(&k  );
    mylib::print_stderr(StrFormat("k = %s", k));
  }
  for (DictIter<BigStr*, int> it(d); !it.Done(); it.Next()) {
    BigStr* k = it.Key();
    int v = it.Value();
    mylib::print_stderr(StrFormat("k = %s, v = %d", k, v));
  }
}
GLOBAL_LIST(CATS, BigStr*, 3, {str29 COMMA str30 COMMA str31});

void run_tests() {
  List<Tuple2<int, BigStr*>*>* list_of_tuples = nullptr;
  int i;
  BigStr* item = nullptr;
  int m;
  int n;
  int index;
  BigStr* s = nullptr;
  List<BigStr*>* list_of_strings = nullptr;
  StackRoot _root0(&list_of_tuples);
  StackRoot _root1(&item);
  StackRoot _root2(&s);
  StackRoot _root3(&list_of_strings);

  mylib::print_stderr(str32);
  for (StrIter it(str33); !it.Done(); it.Next()) {
    BigStr* ch = it.Value();
    StackRoot _for(&ch  );
    mylib::print_stderr(StrFormat("ch = %s", ch));
  }
  mylib::print_stderr(str35);
  for (ListIter<BigStr*> it(NewList<BigStr*>(std::initializer_list<BigStr*>{str36, str37})); !it.Done(); it.Next()) {
    BigStr* item = it.Value();
    StackRoot _for(&item  );
    mylib::print_stderr(StrFormat("item = %s", item));
  }
  mylib::print_stderr(str39);
  list_of_tuples = NewList<Tuple2<int, BigStr*>*>(std::initializer_list<Tuple2<int, BigStr*>*>{(Alloc<Tuple2<int, BigStr*>>(5, str40)), (Alloc<Tuple2<int, BigStr*>>(6, str41))});
  for (ListIter<Tuple2<int, BigStr*>*> it(list_of_tuples); !it.Done(); it.Next()) {
    Tuple2<int, BigStr*>* tup1 = it.Value();
    i = tup1->at0();
    item = tup1->at1();
    mylib::print_stderr(StrFormat("- [%d] %s", i, item));
  }
  mylib::print_stderr(str43);
  m = 2;
  n = 3;
  for (int j = 0; j < (m * 2); ++j) {
    mylib::print_stderr(StrFormat("%d", j));
  }
  mylib::print_stderr(str45);
  for (int k = (m + 2); k < (n + 5); ++k) {
    mylib::print_stderr(StrFormat("%d", k));
  }
  mylib::print_stderr(str47);
  for (int m = 0; m < 5; m += 2) {
    mylib::print_stderr(StrFormat("%d", m));
  }
  mylib::print_stderr(str49);
  for (int m = 0; m > -1; m += -1) {
    mylib::print_stderr(StrFormat("reverse %d", m));
  }
  mylib::print_stderr(str51);
  i = 0;
  for (ListIter<BigStr*> it(CATS); !it.Done(); it.Next(), ++i) {
    BigStr* c = it.Value();
    StackRoot _for(&c  );
    mylib::print_stderr(StrFormat("%d %s", i, c));
  }
  i = 0;
  for (ListIter<Tuple2<int, BigStr*>*> it(list_of_tuples); !it.Done(); it.Next(), ++i) {
    Tuple2<int, BigStr*>* pair = it.Value();
    StackRoot _for(&pair  );
    Tuple2<int, BigStr*>* tup2 = pair;
    index = tup2->at0();
    s = tup2->at1();
    mylib::print_stderr(StrFormat("%d %d %s", i, index, s));
  }
  mylib::print_stderr(str54);
  list_of_strings = NewList<BigStr*>(std::initializer_list<BigStr*>{str55, str56});
  for (ReverseListIter<BigStr*> it(list_of_strings); !it.Done(); it.Next()) {
    BigStr* item = it.Value();
    StackRoot _for(&item  );
    mylib::print_stderr(StrFormat("- %s", item));
  }
  mylib::print_stderr(str58);
  for (ReverseListIter<Tuple2<int, BigStr*>*> it(list_of_tuples); !it.Done(); it.Next()) {
    Tuple2<int, BigStr*>* tup3 = it.Value();
    i = tup3->at0();
    item = tup3->at1();
    mylib::print_stderr(StrFormat("- [%d] %s", i, item));
  }
  TestListComp();
  TestDict();
}

void run_benchmarks() {
  int n;
  int result;
  int i;
  int j;
  n = 500000;
  result = 0;
  i = 0;
  while (i < n) {
    for (int j = 3; j < 10; ++j) {
      result += j;
    }
    j = 0;
    for (ListIter<BigStr*> it(CATS); !it.Done(); it.Next(), ++j) {
      BigStr* c = it.Value();
      StackRoot _for(&c    );
      result += j;
      result += len(c);
    }
    i += 1;
  }
  mylib::print_stderr(StrFormat("result = %d", result));
  mylib::print_stderr(StrFormat("Ran %d iterations of xrange/enumerate", n));
}

}  // define namespace loops

int main(int argc, char **argv) {
  gHeap.Init();

  char* b = getenv("BENCHMARK");
  if (b && strlen(b)) {  // match Python's logic
    fprintf(stderr, "Benchmarking...\n");
    loops::run_benchmarks();
  } else {
    loops::run_tests();
  }

  gHeap.CleanProcessExit();
}