toctave

t(iny)octave
git clone https://0xff.ir/g/toctave.git
Log | Files | Refs | README

cgen.test.cpp (6821B)


      1 
      2 #include "cgen.hpp"
      3 
      4 #include <cassert>
      5 #include <cmath>
      6 #include <iostream>
      7 
      8 #include "env.hpp"
      9 
     10 namespace {
     11 
     12 void
     13 cgen_sexpr()
     14 {
     15   auto i{ 0 };
     16   auto p = [&](const auto& s) {
     17     std::cout << "# " << i << " {\n" << s << "\n# " << i << " }\n";
     18     ++i;
     19   };
     20 
     21   // 0
     22   {
     23     ast::Nodes binop1{ ast::mkop(
     24       ast::Op{ '+' }, ast::mknum(1), ast::mknum(2)) };
     25     auto s{ cgen::sexpr(binop1.begin(), binop1.end()) };
     26 
     27     p(s);
     28     assert(s == "(+ 1 2)");
     29   }
     30 
     31   // 1
     32   {
     33     ast::Nodes ass1{ ast::mkass(
     34       ast::Id{ "x" },
     35       ast::mkop(ast::Op{ '+' },
     36                 ast::mkop(ast::Op{ '/' }, ast::mknum(1), ast::mknum(2)),
     37                 ast::mkop(ast::Op{ '*' }, ast::mknum(3), ast::mknum(4)))) };
     38     auto s{ cgen::sexpr(ass1.begin(), ass1.end()) };
     39 
     40     p(s);
     41     assert(s == "(setq x (+ (/ 1 2) (* 3 4)))");
     42   }
     43 
     44   // 2
     45   {
     46     ast::Nodes eval1{ ast::mkcall(ast::Id{ "eval" },
     47                                   ast::mkstr(ast::Str{ "y = 1 + x" })) };
     48     auto s{ cgen::sexpr(eval1.begin(), eval1.end()) };
     49 
     50     p(s);
     51     assert(s == "(eval \"y = 1 + x\")");
     52   }
     53 }
     54 
     55 void
     56 cgen_jroutine()
     57 {
     58   auto i{ 0 };
     59   auto p = [&](const auto& s) {
     60     std::cout << "# Disasm " << i << " {\n" << s << "# Disasm " << i << " }\n";
     61     ++i;
     62   };
     63 
     64   // 0
     65   {
     66     cgen::JRoutine r;
     67     env::Env e;
     68 
     69     r.push(1.0);
     70     r.push(2.0);
     71     r.add();
     72     r.pop(); /* Moves the result on top of the stack onto `result` */
     73     r.done();
     74 
     75     auto d{ cgen::disasm(r) };
     76 
     77     p(d);
     78     assert(d == R"(     push 1.000000
     79      push 2.000000
     80      add
     81      pop
     82      done
     83 )");
     84 
     85     auto er{ r.mkexec() };
     86 
     87     assert(er.exec(e) == true);
     88     assert(er.result() == 3.0);
     89     assert(e.empty());
     90   }
     91 
     92   // 1
     93   {
     94     cgen::JRoutine r;
     95     env::Env e;
     96 
     97     r.push(3.0);
     98     r.push(4.0);
     99     r.add();
    100     r.push(5.0);
    101     r.mul();
    102     r.pop();
    103     r.done();
    104 
    105     auto d{ cgen::disasm(r) };
    106 
    107     p(d);
    108     assert(d == R"(     push 3.000000
    109      push 4.000000
    110      add
    111      push 5.000000
    112      mul
    113      pop
    114      done
    115 )");
    116 
    117     auto er{ r.mkexec() };
    118 
    119     er.exec(e);
    120     assert(er.result() == 35.0);
    121     assert(e.empty());
    122   }
    123 
    124   // 2
    125   {
    126     cgen::JRoutine r;
    127     env::Env e;
    128 
    129     r.push(3.0);
    130     r.push(4.0);
    131     r.add();
    132     r.popvar("x");
    133     r.push(2.0);
    134     r.pushvar("x");
    135     r.mul();
    136     r.pop();
    137     r.done();
    138 
    139     auto d{ cgen::disasm(r) };
    140 
    141     p(d);
    142     assert(d == R"(     push    3.000000
    143      push    4.000000
    144      add
    145      popvar  x
    146      push    2.000000
    147      pushvar x
    148      mul
    149      pop
    150      done
    151 )");
    152 
    153     auto er{ r.mkexec() };
    154 
    155     assert(er.exec(e) == true);
    156     assert(er.result() == 14.0);
    157     assert(e.size() == 1);
    158     assert(e[0].name == "x");
    159     assert(e[0].val == 7.0);
    160   }
    161 
    162   // 3
    163   {
    164     cgen::JRoutine r;
    165     env::Env e{ { "y", 10.0 } };
    166 
    167     r.push(3.0);
    168     r.push(4.0);
    169     r.pow();
    170     r.popvar("y");
    171     r.push(2.0);
    172     r.pushvar("y");
    173     r.mul();
    174     r.pop();
    175     r.done();
    176 
    177     auto d{ cgen::disasm(r) };
    178 
    179     p(d);
    180     assert(d == R"(     push    3.000000
    181      push    4.000000
    182      pow
    183      popvar  y
    184      push    2.000000
    185      pushvar y
    186      mul
    187      pop
    188      done
    189 )");
    190 
    191     auto er{ r.mkexec() };
    192 
    193     assert(e.size() == 1);
    194     assert(e[0].name == "y");
    195     assert(e[0].val == 10.0);
    196     assert(er.exec(e) == true);
    197     assert(er.result() == 162.0);
    198     assert(e.size() == 1);
    199     assert(e[0].name == "y");
    200     assert(e[0].val == 81.0);
    201   }
    202 
    203   // 4
    204   {
    205     cgen::JRoutine r;
    206     env::Env e;
    207     auto lbl{ r.mklabel() };
    208 
    209     r.push(3.0);
    210     r.push(4.0);
    211     r.add();
    212     r.popvar("x");
    213     r.push(2.0);
    214     r.pop();
    215     r.yield(lbl); // yield the execution, next time it will start from `lbl`
    216     r.label(lbl); // insert the label here
    217     r.push(2.0);
    218     r.pushvar("x");
    219     r.mul();
    220     r.pop();
    221     r.done();
    222 
    223     auto er{ r.mkexec() };
    224     auto d{ cgen::disasm(r) };
    225 
    226     p(d);
    227     assert(d == R"(      push    3.000000
    228       push    4.000000
    229       add
    230       popvar  x
    231       push    2.000000
    232       pop
    233       yield   $L8
    234       exitvm
    235 $L8:  push    2.000000
    236       pushvar x
    237       mul
    238       pop
    239       done
    240       exitvm
    241 )");
    242 
    243     // execution until the yield
    244     assert(er.exec(e) == false);
    245     assert(er.result() == 2.0);
    246     assert(e.size() == 1);
    247     assert(e[0].name == "x");
    248     assert(e[0].val == 7.0);
    249 
    250     // p(cgen::disasm(er));
    251 
    252     // execution after the yield
    253     assert(er.exec(e) == true);
    254     assert(er.result() == 14.0);
    255     assert(e.size() == 1);
    256     assert(e[0].name == "x");
    257     assert(e[0].val == 7.0);
    258   }
    259 }
    260 
    261 void
    262 cgen_jitter()
    263 {
    264   auto i{ 0 };
    265   auto p = [&](const auto& s) {
    266     std::cout << "# Generated code " << i << " {\n"
    267               << s << "# Generated code " << i << " }\n";
    268     ++i;
    269   };
    270 
    271   // 0
    272   {
    273     ast::Nodes num1{ ast::mknum(120) };
    274     auto j{ cgen::jitter(num1.begin(), num1.end()) };
    275     auto s{ cgen::disasm(j) };
    276     auto je{ j.mkexec() };
    277     env::Env env;
    278 
    279     p(s);
    280     assert(s == R"(     push 120.000000
    281      pop
    282      done
    283 )");
    284     je.exec(env);
    285     assert(env.empty());
    286     assert(je.result() == 120.0);
    287   }
    288 
    289   // 1
    290   {
    291     ast::Nodes binop1{ ast::mkop(
    292       ast::Op{ '+' }, ast::mknum(1), ast::mknum(2)) };
    293     auto j{ cgen::jitter(binop1.begin(), binop1.end()) };
    294     auto s{ cgen::disasm(j) };
    295     auto je{ j.mkexec() };
    296     env::Env env;
    297 
    298     p(s);
    299     assert(s == R"(     push 1.000000
    300      push 2.000000
    301      add
    302      pop
    303      done
    304 )");
    305     assert(je.exec(env) == true);
    306     assert(env.empty());
    307     assert(je.result() == 3.0);
    308   }
    309 
    310   // 2
    311   {
    312     ast::Nodes ass1{ ast::mkass(
    313       ast::Id{ "x" },
    314       ast::mkop(ast::Op{ '+' },
    315                 ast::mkop(ast::Op{ '/' }, ast::mknum(1), ast::mknum(2)),
    316                 ast::mkop(ast::Op{ '*' }, ast::mknum(3), ast::mknum(4)))) };
    317     auto j{ cgen::jitter(ass1.begin(), ass1.end()) };
    318     auto s{ cgen::disasm(j) };
    319     auto je{ j.mkexec() };
    320     env::Env env;
    321     double d{ 0.0 };
    322 
    323     p(s);
    324     assert(s != R"(       push    1.000000
    325       push    2.000000
    326       div
    327       push    3.000000
    328       push    4.000000
    329       mul
    330       add
    331       popvar  x
    332       pushnan
    333       pop
    334       done
    335 )");
    336     assert(je.exec(env) == true);
    337     assert(std::isnan(je.result()));
    338     assert(env.size() == 1);
    339     assert(toctave_var(&env, "x", &d));
    340     assert(d == 12.5);
    341   }
    342 
    343   if (0) {
    344     ast::Nodes eval1{ ast::mkcall(ast::Id{ "eval" },
    345                                   ast::mkstr(ast::Str{ "y = 1 + x" })) };
    346     auto j{ cgen::jitter(eval1.begin(), eval1.end()) };
    347     auto s{ cgen::disasm(j) };
    348 
    349     p(s);
    350   }
    351 }
    352 
    353 } // anonymous namespace
    354 
    355 int
    356 main()
    357 {
    358   // To manage VM initialization/deintialization process
    359   // (this is like a ScopeGuard)
    360   std::unique_ptr<void, void (*)(void*)> vm_init(
    361     [] {
    362       toctave_initialize();
    363       return reinterpret_cast<void*>(1); /* dummy */
    364     }(),
    365     [](void*) { toctave_finalize(); });
    366 
    367   cgen_sexpr();
    368   cgen_jroutine();
    369   cgen_jitter();
    370   return 0;
    371 }