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 }