"Fossies" - the Fresh Open Source Software Archive

Member "ponyc-0.33.2/test/libponyc/codegen.cc" (3 Feb 2020, 20956 Bytes) of package /linux/misc/ponyc-0.33.2.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "codegen.cc": 0.33.1_vs_0.33.2.

    1 #include <gtest/gtest.h>
    2 #include <platform.h>
    3 
    4 #include <codegen/gentype.h>
    5 #include <../libponyrt/mem/pool.h>
    6 
    7 #include "util.h"
    8 
    9 #include "llvm_config_begin.h"
   10 
   11 #include <llvm/IR/Constants.h>
   12 #include <llvm/IR/Module.h>
   13 
   14 #include "llvm_config_end.h"
   15 
   16 #define TEST_COMPILE(src) DO(test_compile(src, "ir"))
   17 
   18 
   19 class CodegenTest : public PassTest
   20 {
   21 };
   22 
   23 
   24 TEST_F(CodegenTest, PackedStructIsPacked)
   25 {
   26   const char* src =
   27     "struct \\packed\\ Foo\n"
   28     "  var a: U8 = 0\n"
   29     "  var b: U32 = 0\n"
   30 
   31     "actor Main\n"
   32     "  new create(env: Env) =>\n"
   33     "    Foo";
   34 
   35   TEST_COMPILE(src);
   36 
   37   reach_t* reach = compile->reach;
   38   reach_type_t* foo = reach_type_name(reach, "Foo");
   39   ASSERT_TRUE(foo != NULL);
   40 
   41   LLVMTypeRef type = ((compile_type_t*)foo->c_type)->structure;
   42   ASSERT_TRUE(LLVMIsPackedStruct(type));
   43 }
   44 
   45 
   46 TEST_F(CodegenTest, NonPackedStructIsntPacked)
   47 {
   48   const char* src =
   49     "struct Foo\n"
   50     "  var a: U8 = 0\n"
   51     "  var b: U32 = 0\n"
   52 
   53     "actor Main\n"
   54     "  new create(env: Env) =>\n"
   55     "    Foo";
   56 
   57   TEST_COMPILE(src);
   58 
   59   reach_t* reach = compile->reach;
   60   reach_type_t* foo = reach_type_name(reach, "Foo");
   61   ASSERT_TRUE(foo != NULL);
   62 
   63   LLVMTypeRef type = ((compile_type_t*)foo->c_type)->structure;
   64   ASSERT_TRUE(!LLVMIsPackedStruct(type));
   65 }
   66 
   67 
   68 TEST_F(CodegenTest, JitRun)
   69 {
   70   const char* src =
   71     "actor Main\n"
   72     "  new create(env: Env) =>\n"
   73     "    @pony_exitcode[None](I32(1))";
   74 
   75   TEST_COMPILE(src);
   76 
   77   int exit_code = 0;
   78   ASSERT_TRUE(run_program(&exit_code));
   79   ASSERT_EQ(exit_code, 1);
   80 }
   81 
   82 
   83 TEST_F(CodegenTest, BoxBoolAsUnionIntoTuple)
   84 {
   85   // From #2191
   86   const char* src =
   87     "type U is (Bool | C)\n"
   88 
   89     "class C\n"
   90     "  fun apply(): (I32, U) =>\n"
   91     "    (0, false)\n"
   92 
   93     "actor Main\n"
   94     "  new create(env: Env) =>\n"
   95     "    C()";
   96 
   97   TEST_COMPILE(src);
   98 
   99   ASSERT_TRUE(compile != NULL);
  100 }
  101 
  102 
  103 extern "C"
  104 {
  105 
  106 static uint32_t num_objects = 0;
  107 
  108 EXPORT_SYMBOL void codegentest_small_finalisers_increment_num_objects() {
  109   num_objects++;
  110   pony_exitcode((int)num_objects);
  111 }
  112 
  113 }
  114 
  115 
  116 TEST_F(CodegenTest, SmallFinalisers)
  117 {
  118   const char* src =
  119     "class _Final\n"
  120     "  fun _final() =>\n"
  121     "    @codegentest_small_finalisers_increment_num_objects[None]()\n"
  122 
  123     "actor Main\n"
  124     "  new create(env: Env) =>\n"
  125     "    var i: U64 = 0\n"
  126     "    while i < 42 do\n"
  127     "      _Final\n"
  128     "      i = i + 1\n"
  129     "    end";
  130 
  131   TEST_COMPILE(src);
  132 
  133   int exit_code = 0;
  134   ASSERT_TRUE(run_program(&exit_code));
  135   ASSERT_EQ(exit_code, 42);
  136 }
  137 
  138 
  139 extern "C"
  140 {
  141 
  142 typedef int (*codegentest_ccallback_fn)(void* self, int value);
  143 
  144 EXPORT_SYMBOL int codegentest_ccallback(void* self, codegentest_ccallback_fn cb,
  145   int value)
  146 {
  147   return cb(self, value);
  148 }
  149 
  150 }
  151 
  152 
  153 TEST_F(CodegenTest, CCallback)
  154 {
  155   const char* src =
  156     "class Callback\n"
  157     "  fun apply(value: I32): I32 =>\n"
  158     "    value * 2\n"
  159 
  160     "actor Main\n"
  161     "  new create(env: Env) =>\n"
  162     "    let cb: Callback = Callback\n"
  163     "    let r = @codegentest_ccallback[I32](cb, addressof cb.apply, I32(3))\n"
  164     "    @pony_exitcode[None](r)";
  165 
  166   TEST_COMPILE(src);
  167 
  168   int exit_code = 0;
  169   ASSERT_TRUE(run_program(&exit_code));
  170   ASSERT_EQ(exit_code, 6);
  171 }
  172 
  173 TEST_F(CodegenTest, MatchExhaustiveAllCasesOfUnion)
  174 {
  175   const char* src =
  176     "class C1 fun one(): I32 => 1\n"
  177     "class C2 fun two(): I32 => 2\n"
  178     "class C3 fun three(): I32 => 3\n"
  179 
  180     "primitive Foo\n"
  181     "  fun apply(c': (C1 | C2 | C3)): I32 =>\n"
  182     "    match c'\n"
  183     "    | let c: C1 => c.one()\n"
  184     "    | let c: C2 => c.two()\n"
  185     "    | let c: C3 => c.three()\n"
  186     "    end\n"
  187 
  188     "actor Main\n"
  189     "  new create(env: Env) =>\n"
  190     "    @pony_exitcode[None](Foo(C3))";
  191 
  192   TEST_COMPILE(src);
  193 
  194   int exit_code = 0;
  195   ASSERT_TRUE(run_program(&exit_code));
  196   ASSERT_EQ(exit_code, 3);
  197 }
  198 
  199 
  200 TEST_F(CodegenTest, MatchExhaustiveAllCasesIncludingDontCareAndTuple)
  201 {
  202   const char* src =
  203     "class C1 fun one(): I32 => 1\n"
  204     "class C2 fun two(): I32 => 2\n"
  205     "class C3 fun three(): I32 => 3\n"
  206 
  207     "primitive Foo\n"
  208     "  fun apply(c': (C1 | C2 | (C3, Bool))): I32 =>\n"
  209     "    match c'\n"
  210     "    | let c: C1 => c.one()\n"
  211     "    | let _: C2 => 2\n"
  212     "    | (let c: C3, let _: Bool) => c.three()\n"
  213     "    end\n"
  214 
  215     "actor Main\n"
  216     "  new create(env: Env) =>\n"
  217     "    @pony_exitcode[None](Foo((C3, true)))";
  218   TEST_COMPILE(src);
  219 
  220   int exit_code = 0;
  221   ASSERT_TRUE(run_program(&exit_code));
  222   ASSERT_EQ(exit_code, 3);
  223 }
  224 
  225 
  226 TEST_F(CodegenTest, MatchExhaustiveAllCasesPrimitiveValues)
  227 {
  228   const char* src =
  229     "primitive P1 fun one(): I32 => 1\n"
  230     "primitive P2 fun two(): I32 => 2\n"
  231     "primitive P3 fun three(): I32 => 3\n"
  232 
  233     "primitive Foo\n"
  234     "  fun apply(p': (P1 | P2 | P3)): I32 =>\n"
  235     "    match p'\n"
  236     "    | let p: P1 => p.one()\n"
  237     "    | let p: P2 => p.two()\n"
  238     "    | let p: P3 => p.three()\n"
  239     "    end\n"
  240 
  241     "actor Main\n"
  242     "  new create(env: Env) =>\n"
  243     "    @pony_exitcode[None](Foo(P3))";
  244 
  245   TEST_COMPILE(src);
  246 
  247   int exit_code = 0;
  248   ASSERT_TRUE(run_program(&exit_code));
  249   ASSERT_EQ(exit_code, 3);
  250 }
  251 
  252 
  253 TEST_F(CodegenTest, ArrayInfersMostSpecificFromUnionOfArrayTypes)
  254 {
  255   const char* src =
  256     "trait iso T1\n"
  257     "trait iso T2\n"
  258     "trait iso T3 is T1\n"
  259     "trait iso T4 is T2\n"
  260     "class iso C1 is T3\n"
  261     "class iso C2 is T4\n"
  262 
  263     "primitive Foo\n"
  264     "  fun apply(): (Array[T1] | Array[T2] | Array[T3] | Array[T4]) =>\n"
  265     "    [C1]\n"
  266 
  267     "actor Main\n"
  268     "  new create(env: Env) =>\n"
  269     "    match Foo() \n"
  270     "    | let a: Array[T1] => @pony_exitcode[None](I32(1))\n"
  271     "    | let a: Array[T2] => @pony_exitcode[None](I32(2))\n"
  272     "    | let a: Array[T3] => @pony_exitcode[None](I32(3))\n"
  273     "    | let a: Array[T4] => @pony_exitcode[None](I32(4))\n"
  274     "    end";
  275 
  276   TEST_COMPILE(src);
  277 
  278   int exit_code = 0;
  279   ASSERT_TRUE(run_program(&exit_code));
  280   ASSERT_EQ(exit_code, 3);
  281 }
  282 
  283 
  284 TEST_F(CodegenTest, UnionOfTuplesToTuple)
  285 {
  286   const char* src =
  287     "actor Main\n"
  288     "  new create(env: Env) =>\n"
  289     "    let a: ((Main, Env) | (Env, Main)) = (this, env)\n"
  290     "    let b: ((Main | Env), (Main | Env)) = a";
  291 
  292   TEST_COMPILE(src);
  293 }
  294 
  295 
  296 TEST_F(CodegenTest, ViewpointAdaptedFieldReach)
  297 {
  298   // From issue #2238
  299   const char* src =
  300     "class A\n"
  301     "class B\n"
  302     "  var f: (A | None) = None\n"
  303 
  304     "actor Main\n"
  305     "  new create(env: Env) =>\n"
  306     "    let l = B\n"
  307     "    l.f = A";
  308 
  309   TEST_COMPILE(src);
  310 }
  311 
  312 
  313 TEST_F(CodegenTest, StringSerialization)
  314 {
  315   // From issue #2245
  316   const char* src =
  317     "use \"serialise\"\n"
  318 
  319     "class V\n"
  320     "  let _v: String = \"\"\n"
  321 
  322     "actor Main\n"
  323     "  new create(env: Env) =>\n"
  324     "    try\n"
  325     "      let auth = env.root as AmbientAuth\n"
  326     "      let v: V = V\n"
  327     "      Serialised(SerialiseAuth(auth), v)?\n"
  328     "      @pony_exitcode[None](I32(1))\n"
  329     "    end";
  330 
  331   set_builtin(NULL);
  332 
  333   TEST_COMPILE(src);
  334 
  335   int exit_code = 0;
  336   ASSERT_TRUE(run_program(&exit_code));
  337   ASSERT_EQ(exit_code, 1);
  338 }
  339 
  340 
  341 TEST_F(CodegenTest, CustomSerialization)
  342 {
  343   const char* src =
  344     "use \"serialise\"\n"
  345 
  346     "class _Custom\n"
  347     "  let s1: String = \"abc\"\n"
  348     "  var p: Pointer[U8]\n"
  349     "  let s2: String = \"efg\"\n"
  350 
  351     "  new create() =>\n"
  352     "    p = @test_custom_serialisation_get_object[Pointer[U8] ref]()\n"
  353 
  354     "  fun _final() =>\n"
  355     "    @test_custom_serialisation_free_object[None](p)\n"
  356 
  357     "  fun _serialise_space(): USize =>\n"
  358     "    8\n"
  359 
  360     "  fun _serialise(bytes: Pointer[U8]) =>\n"
  361     "    @test_custom_serialisation_serialise[None](p, bytes)\n"
  362 
  363     "  fun ref _deserialise(bytes: Pointer[U8]) =>\n"
  364     "    p = @test_custom_serialisation_deserialise[Pointer[U8] ref](bytes)\n"
  365 
  366     "  fun eq(c: _Custom): Bool =>\n"
  367     "    (@test_custom_serialisation_compare[U8](this.p, c.p) == 1) and\n"
  368     "    (this.s1 == c.s1)\n"
  369     "      and (this.s2 == c.s2)\n"
  370 
  371     "actor Main\n"
  372     "  new create(env: Env) =>\n"
  373     "    try\n"
  374     "      let ambient = env.root as AmbientAuth\n"
  375     "      let serialise = SerialiseAuth(ambient)\n"
  376     "      let deserialise = DeserialiseAuth(ambient)\n"
  377 
  378     "      let x: _Custom = _Custom\n"
  379     "      let sx = Serialised(serialise, x)?\n"
  380     "      let yd: Any ref = sx(deserialise)?\n"
  381     "      let y = yd as _Custom\n"
  382     "      let r: I32 = if (x isnt y) and (x == y) then\n"
  383     "        1\n"
  384     "      else\n"
  385     "        0\n"
  386     "      end\n"
  387     "      @pony_exitcode[None](r)\n"
  388     "    end";
  389 
  390   set_builtin(NULL);
  391 
  392   TEST_COMPILE(src);
  393 
  394   int exit_code = 0;
  395   ASSERT_TRUE(run_program(&exit_code));
  396   ASSERT_EQ(exit_code, 1);
  397 }
  398 
  399 
  400 extern "C"
  401 {
  402 
  403 EXPORT_SYMBOL void* test_custom_serialisation_get_object()
  404 {
  405   uint64_t* i = POOL_ALLOC(uint64_t);
  406   *i = 0xDEADBEEF10ADBEE5;
  407   return i;
  408 }
  409 
  410 EXPORT_SYMBOL void test_custom_serialisation_free_object(uint64_t* p)
  411 {
  412   POOL_FREE(uint64_t, p);
  413 }
  414 
  415 EXPORT_SYMBOL void test_custom_serialisation_serialise(uint64_t* p,
  416   unsigned char* bytes)
  417 {
  418   *(uint64_t*)(bytes) = *p;
  419 }
  420 
  421 EXPORT_SYMBOL void* test_custom_serialisation_deserialise(unsigned char* bytes)
  422 {
  423   uint64_t* p = POOL_ALLOC(uint64_t);
  424   *p = *(uint64_t*)(bytes);
  425   return p;
  426 }
  427 
  428 EXPORT_SYMBOL char test_custom_serialisation_compare(uint64_t* p1, uint64_t* p2)
  429 {
  430   return *p1 == *p2;
  431 }
  432 
  433 }
  434 
  435 
  436 TEST_F(CodegenTest, DoNotOptimiseApplyPrimitive)
  437 {
  438   const char* src =
  439     "actor Main\n"
  440     "  new create(env: Env) =>\n"
  441     "    DoNotOptimise[I64](0)";
  442 
  443   TEST_COMPILE(src);
  444 }
  445 
  446 
  447 // Doesn't work on windows. The C++ code doesn't catch C++ exceptions if they've
  448 // traversed a Pony frame. This is suspected to be related to how SEH and LLVM
  449 // exception code generation interact.
  450 // See https://github.com/ponylang/ponyc/issues/2455 for more details.
  451 //
  452 // This test is disabled on LLVM 3.9 and 4.0 because exceptions crossing JIT
  453 // boundaries are broken with the ORC JIT on these versions.
  454 #if !defined(PLATFORM_IS_WINDOWS) && (PONY_LLVM >= 500) && (PONY_LLVM < 900)
  455 TEST_F(CodegenTest, TryBlockCantCatchCppExcept)
  456 {
  457   const char* src =
  458     "actor Main\n"
  459     "  new create(env: Env) =>\n"
  460     "    let r = @codegen_test_tryblock_catch[I32](this~tryblock())\n"
  461     "    @pony_exitcode[I32](r)\n"
  462 
  463     "  fun @tryblock() =>\n"
  464     "    try\n"
  465     "      @codegen_test_tryblock_throw[None]()?\n"
  466     "    else\n"
  467     "      None\n"
  468     "    end";
  469 
  470   TEST_COMPILE(src);
  471 
  472   int exit_code = 0;
  473   ASSERT_TRUE(run_program(&exit_code));
  474   ASSERT_EQ(exit_code, 1);
  475 }
  476 
  477 
  478 extern "C"
  479 {
  480 
  481 EXPORT_SYMBOL int codegen_test_tryblock_catch(void (*callback)())
  482 {
  483   try
  484   {
  485     callback();
  486     return 0;
  487   } catch(std::exception const&) {
  488     return 1;
  489   }
  490 }
  491 
  492 EXPORT_SYMBOL void codegen_test_tryblock_throw()
  493 {
  494   throw std::exception{};
  495 }
  496 
  497 }
  498 #endif
  499 
  500 
  501 TEST_F(CodegenTest, DescTable)
  502 {
  503   const char* src =
  504     "class C1\n"
  505     "class C2\n"
  506     "class C3\n"
  507     "actor A1\n"
  508     "actor A2\n"
  509     "actor A3\n"
  510     "primitive P1\n"
  511     "primitive P2\n"
  512     "primitive P3\n"
  513 
  514     "actor Main\n"
  515     "  new create(env: Env) =>\n"
  516 
  517   // Reach various types.
  518 
  519     "    (C1, A1, P1)\n"
  520     "    (C2, A2, P2)\n"
  521     "    (C3, A3, P3)\n"
  522     "    (C1, I8)\n"
  523     "    (C2, I16)\n"
  524     "    (C3, I32)";
  525 
  526   TEST_COMPILE(src);
  527 
  528   auto module = llvm::unwrap(compile->module);
  529 
  530   auto table_glob = module->getNamedGlobal("__DescTable");
  531   ASSERT_NE(table_glob, nullptr);
  532   ASSERT_TRUE(table_glob->hasInitializer());
  533 
  534   auto desc_table = llvm::dyn_cast_or_null<llvm::ConstantArray>(
  535     table_glob->getInitializer());
  536   ASSERT_NE(desc_table, nullptr);
  537 
  538   for(unsigned int i = 0; i < desc_table->getNumOperands(); i++)
  539   {
  540     // Check that for each element of the table, `desc_table[i]->id == i`.
  541 
  542     auto table_element = desc_table->getOperand(i);
  543     ASSERT_EQ(table_element->getType(), llvm::unwrap(compile->descriptor_ptr));
  544 
  545     if(table_element->isNullValue())
  546       continue;
  547 
  548     auto elt_bitcast = llvm::dyn_cast_or_null<llvm::ConstantExpr>(
  549       table_element);
  550     ASSERT_NE(elt_bitcast, nullptr);
  551     ASSERT_EQ(elt_bitcast->getOpcode(), llvm::Instruction::BitCast);
  552 
  553     auto desc_ptr = llvm::dyn_cast_or_null<llvm::GlobalVariable>(
  554       elt_bitcast->getOperand(0));
  555     ASSERT_NE(desc_ptr, nullptr);
  556     ASSERT_TRUE(desc_ptr->hasInitializer());
  557 
  558     auto desc = llvm::dyn_cast_or_null<llvm::ConstantStruct>(
  559       desc_ptr->getInitializer());
  560     ASSERT_NE(desc, nullptr);
  561 
  562     auto type_id = llvm::dyn_cast_or_null<llvm::ConstantInt>(
  563       desc->getOperand(0));
  564     ASSERT_NE(type_id, nullptr);
  565 
  566     ASSERT_EQ(type_id->getBitWidth(), 32);
  567     ASSERT_EQ(type_id->getZExtValue(), i);
  568   }
  569 }
  570 
  571 
  572 TEST_F(CodegenTest, RecoverCast)
  573 {
  574   // From issue #2639
  575   const char* src =
  576     "class A\n"
  577     "  new create() => None\n"
  578 
  579     "actor Main\n"
  580     "  new create(env: Env) =>\n"
  581     "    let x: ((None, None) | (A iso, None)) =\n"
  582     "      if false then\n"
  583     "        (None, None)\n"
  584     "      else\n"
  585     "        recover (A, None) end\n"
  586     "      end";
  587 
  588   TEST_COMPILE(src);
  589 }
  590 
  591 TEST_F(CodegenTest, VariableDeclNestedTuple)
  592 {
  593   // From issue #2662
  594   const char* src =
  595     "actor Main\n"
  596     "  new create(env: Env) =>\n"
  597     "    let array = Array[((U8, U8), U8)]\n"
  598     "    for ((a, b), c) in array.values() do\n"
  599     "      None\n"
  600     "    end";
  601 
  602   TEST_COMPILE(src);
  603 }
  604 
  605 TEST_F(CodegenTest, TupleRemoveUnreachableBlockInLoop)
  606 {
  607   // From issue #2760
  608   const char* src =
  609     "actor Main\n"
  610     "  new create(env: Env) =>\n"
  611     "    var token = U8(1)\n"
  612     "    repeat\n"
  613     "      (token, let source) = (U8(1), U8(2))\n"
  614     "    until token == 2 end";
  615 
  616   TEST_COMPILE(src);
  617 }
  618 
  619 TEST_F(CodegenTest, TupleRemoveUnreachableBlock)
  620 {
  621   // From issue #2735
  622   const char* src =
  623     "actor Main\n"
  624     "  new create(env: Env) =>\n"
  625     "    if true then\n"
  626     "      (let f, let g) = (U8(2), U8(3))\n"
  627     "    end";
  628 
  629   TEST_COMPILE(src);
  630 }
  631 
  632 TEST_F(CodegenTest, RedundantUnionInForLoopIteratorValueType)
  633 {
  634   // From issue #2736
  635   const char* src =
  636     "type T is (U8 | U8)\n"
  637 
  638     "actor Main\n"
  639     "  new create(env: Env) =>\n"
  640     "    let i = I\n"
  641     "    for m in i do\n"
  642     "      None\n"
  643     "    end\n"
  644 
  645     "class ref I is Iterator[T]\n"
  646     "  new create() => None\n"
  647     "  fun ref has_next(): Bool => false\n"
  648     "  fun ref next(): T ? => error";
  649 
  650   TEST_COMPILE(src);
  651 }
  652 
  653 TEST_F(CodegenTest, WhileLoopBreakOnlyValueNeeded)
  654 {
  655   // From issue #2788
  656   const char* src =
  657     "actor Main\n"
  658       "new create(env: Env) =>\n"
  659         "let x = while true do break true else false end\n"
  660         "if x then None end";
  661 
  662   TEST_COMPILE(src);
  663 }
  664 
  665 TEST_F(CodegenTest, WhileLoopBreakOnlyInBranches)
  666 {
  667   // From issue #2788
  668   const char* src =
  669     "actor Main\n"
  670       "new create(env: Env) =>\n"
  671         "while true do\n"
  672           "if true then\n"
  673             "break None\n"
  674           "else\n"
  675             "break\n"
  676           "end\n"
  677         "else\n"
  678           "return\n"
  679         "end";
  680 
  681   TEST_COMPILE(src);
  682 }
  683 
  684 TEST_F(CodegenTest, RepeatLoopBreakOnlyValueNeeded)
  685 {
  686   // From issue #2788
  687   const char* src =
  688     "actor Main\n"
  689       "new create(env: Env) =>\n"
  690         "let x = repeat break true until false else false end\n"
  691         "if x then None end";
  692 
  693   TEST_COMPILE(src);
  694 }
  695 
  696 TEST_F(CodegenTest, RepeatLoopBreakOnlyInBranches)
  697 {
  698   // From issue #2788
  699   const char* src =
  700     "actor Main\n"
  701       "new create(env: Env) =>\n"
  702         "repeat\n"
  703           "if true then\n"
  704             "break None\n"
  705           "else\n"
  706             "break\n"
  707           "end\n"
  708         "until\n"
  709           "false\n"
  710         "else\n"
  711           "return\n"
  712         "end";
  713 
  714   TEST_COMPILE(src);
  715 }
  716 
  717 TEST_F(CodegenTest, CycleDetector)
  718 {
  719   const char* src =
  720     "actor Ring\n"
  721     "  let _id: U32\n"
  722     "  var _next: (Ring | None)\n"
  723 
  724     "  new create(id: U32, neighbor: (Ring | None) = None) =>\n"
  725     "    _id = id\n"
  726     "    _next = neighbor\n"
  727 
  728     "  be set(neighbor: Ring) =>\n"
  729     "    _next = neighbor\n"
  730 
  731     "  be pass(i: USize) =>\n"
  732     "    if i > 0 then\n"
  733     "      match _next\n"
  734     "      | let n: Ring =>\n"
  735     "        n.pass(i - 1)\n"
  736     "      end\n"
  737     "    end\n"
  738 
  739     "  fun _final() =>\n"
  740     "    let i = @pony_get_exitcode[I32]()\n"
  741     "    @pony_exitcode[None](i + 1)\n"
  742 
  743     "actor Watcher\n"
  744     "  var _c: I32 = 0\n"
  745     "  new create(num: I32) => check_done(num)\n"
  746 
  747     "  be check_done(num: I32) =>\n"
  748     "    if @pony_get_exitcode[I32]() != num then\n"
  749     "      /* wait for cycle detector to reap ring actors */\n"
  750     "      ifdef windows then\n"
  751     "        @Sleep[None](U32(30))\n"
  752     "      else\n"
  753     "        @ponyint_cpu_core_pause[None](U64(0), U64(20000000000), true)\n"
  754     "      end\n"
  755     "      _c = _c + 1\n"
  756     "      if _c > 50 then\n"
  757     "        @printf[I32](\"Ran out of time... exit count is: %d instead of %d\n\".cstring(), @pony_get_exitcode[I32](), num)\n"
  758     "        @pony_exitcode[None](I32(1))\n"
  759     "      else\n"
  760     "        check_done(num)\n"
  761     "      end\n"
  762     "    else\n"
  763     "      @pony_exitcode[None](I32(0))\n"
  764     "    end\n"
  765 
  766 
  767     "actor Main\n"
  768     "  var _ring_size: U32 = 100\n"
  769     "  var _ring_count: U32 = 100\n"
  770     "  var _pass: USize = 10\n"
  771 
  772     "  new create(env: Env) =>\n"
  773     "    setup_ring()\n"
  774     "    Watcher((_ring_size * _ring_count).i32())\n"
  775 
  776     "  fun setup_ring() =>\n"
  777     "    var j: U32 = 0\n"
  778     "    while true do\n"
  779     "      let first = Ring(1)\n"
  780     "      var next = first\n"
  781 
  782     "      var k: U32 = 0\n"
  783     "      while true do\n"
  784     "        let current = Ring(_ring_size - k, next)\n"
  785     "        next = current\n"
  786 
  787     "        k = k + 1\n"
  788     "        if k >= (_ring_size - 1) then\n"
  789     "          break\n"
  790     "        end\n"
  791     "      end\n"
  792 
  793     "      first.set(next)\n"
  794 
  795     "      if _pass > 0 then\n"
  796     "        first.pass(_pass)\n"
  797     "      end\n"
  798 
  799     "      j = j + 1\n"
  800     "      if j >= _ring_count then\n"
  801     "        break\n"
  802     "      end\n"
  803     "    end\n";
  804 
  805   set_builtin(NULL);
  806 
  807   TEST_COMPILE(src);
  808 
  809   int exit_code = -1;
  810   ASSERT_TRUE(run_program(&exit_code));
  811   ASSERT_EQ(exit_code, 0);
  812 }
  813 
  814 TEST_F(CodegenTest, TryThenClauseReturn)
  815 {
  816   const char * src =
  817     "actor Main\n"
  818     "  new create(env: Env) =>\n"
  819     "    try\n"
  820     "      if false then error end\n"
  821     "      return\n"
  822     "    then\n"
  823     "      @pony_exitcode[None](I32(42))"
  824     "    end\n"
  825     "    @pony_exitcode[None](I32(0))";
  826 
  827   TEST_COMPILE(src);
  828 
  829   int exit_code = -1;
  830   ASSERT_TRUE(run_program(&exit_code));
  831   ASSERT_EQ(exit_code, 42);
  832 }
  833 
  834 TEST_F(CodegenTest, TryThenClauseReturnNested)
  835 {
  836   const char * src =
  837     "actor Main\n"
  838     "  new create(env: Env) =>\n"
  839     "    try\n"
  840     "      try\n"
  841     "        if false then error end\n"
  842     "        return\n"
  843     "      end\n"
  844     "    then\n"
  845     "      @pony_exitcode[None](I32(42))"
  846     "    end\n"
  847     "    @pony_exitcode[None](I32(0))";
  848 
  849   TEST_COMPILE(src);
  850 
  851   int exit_code = -1;
  852   ASSERT_TRUE(run_program(&exit_code));
  853   ASSERT_EQ(exit_code, 42);
  854 }
  855 
  856 TEST_F(CodegenTest, TryThenClauseBreak)
  857 {
  858   const char * src =
  859     "actor Main\n"
  860     "  new create(env: Env) =>\n"
  861     "    var r: I32 = 0\n"
  862     "    while true do\n"
  863     "      try\n"
  864     "        if Bool(false) then error end\n"
  865     "        break\n"
  866     "      then\n"
  867     "        r = 42\n"
  868     "      end\n"
  869     "    end\n"
  870     "    @pony_exitcode[None](r)";
  871   TEST_COMPILE(src);
  872 
  873   int exit_code = 0;
  874   ASSERT_TRUE(run_program(&exit_code));
  875   ASSERT_EQ(exit_code, 42);
  876 }
  877 
  878 TEST_F(CodegenTest, TryThenClauseBreakNested)
  879 {
  880   const char * src =
  881     "actor Main\n"
  882     "  new create(env: Env) =>\n"
  883     "    var r: I32 = 0\n"
  884     "    while true do\n"
  885     "      try\n"
  886     "        try\n"
  887     "          if Bool(false) then error end\n"
  888     "          break\n"
  889     "        end\n"
  890     "      then\n"
  891     "        r = 42\n"
  892     "      end\n"
  893     "    end\n"
  894     "    @pony_exitcode[None](r)";
  895   TEST_COMPILE(src);
  896 
  897   int exit_code = 0;
  898   ASSERT_TRUE(run_program(&exit_code));
  899   ASSERT_EQ(exit_code, 42);
  900 }
  901 
  902 TEST_F(CodegenTest, TryThenClauseContinue)
  903 {
  904   const char * src =
  905     "actor Main\n"
  906     "  new create(env: Env) =>\n"
  907     "    var r: I32 = 0\n"
  908     "    while r == 0 do\n"
  909     "      try\n"
  910     "        if Bool(false) then error else r = 1 end\n"
  911     "        continue\n"
  912     "      then\n"
  913     "        r = 42\n"
  914     "      end\n"
  915     "    end\n"
  916     "    @pony_exitcode[None](r)";
  917   TEST_COMPILE(src);
  918 
  919   int exit_code = 0;
  920   ASSERT_TRUE(run_program(&exit_code));
  921   ASSERT_EQ(exit_code, 42);
  922 }
  923 
  924 TEST_F(CodegenTest, TryThenClauseContinueNested)
  925 {
  926   const char * src =
  927     "actor Main\n"
  928     "  new create(env: Env) =>\n"
  929     "    var r: I32 = 0\n"
  930     "    while r == 0 do\n"
  931     "      try\n"
  932     "        if Bool(true) then\n"
  933     "          try\n"
  934     "            if Bool(false) then error else r = 1 end\n"
  935     "            continue\n"
  936     "          end\n"
  937     "        end\n"
  938     "      then\n"
  939     "        r = 42\n"
  940     "      end\n"
  941     "    end\n"
  942     "    @pony_exitcode[None](r)";
  943   TEST_COMPILE(src);
  944 
  945   int exit_code = 0;
  946   ASSERT_TRUE(run_program(&exit_code));
  947   ASSERT_EQ(exit_code, 42);
  948 }