11#include < string>
2+ #include < iterator>
23#include < iomanip> // TODO remove
34#include < fstream>
45#include < stdexcept>
56#include < iostream>
7+ #include < functional>
8+
69#include " runtime.hpp"
10+ #include " bridge.hpp"
711
8- static void NYI (std::string const & add = " " ) {
12+ [[noreturn]] static void NYI (std::string const & add = " " ) {
913 throw std::runtime_error (" Not Yet Implemented, sorry! " + add);
1014}
1115
1216using json = nlohmann::json;
1317
1418namespace testml {
1519
16- Runtime::Runtime (std::string const & filename) {
20+ namespace {
21+ bool is_all_lowercase (std::string const & s) {
22+ return std::all_of (s.begin (), s.end (), [](char c) { return std::islower (c); });
23+ }
24+ }
25+
26+ Runtime::Runtime (std::string const & filename, Bridge& bridge)
27+ : _bridge{bridge} {
28+
1729 std::ifstream stream (filename);
1830 stream >> _ast;
1931
2032 _data = _ast[" data" ];
2133 }
2234
23- json Runtime::exec_expr (json:: array_t fragment) {
35+ json Runtime::exec_expr (json fragment) {
2436 if (!fragment.is_array () || fragment.size () == 0 )
25- return fragment;
37+ return json::array_t {fragment};
38+
39+ // TODO check if the first element is a string, otherwise return it unwrapped
2640
27- auto opcode = fragment[0 ];
41+ std::string opcode = fragment[0 ];
2842 fragment.erase (fragment.begin ()); // pop first arg
2943 json val;
3044 if (opcode == " %<>" ) {
@@ -33,23 +47,29 @@ namespace testml {
3347 each_pick (fragment[0 ], fragment[1 ]);
3448 return {}; // no return value
3549 } else if (opcode == " ==" ) {
36- assert_eq (fragment[0 ], fragment[1 ], fragment.size () == 3 ? fragment[2 ] : " (no reason) " );
50+ assert_eq (fragment[0 ], fragment[1 ], fragment.size () == 3 ? fragment[2 ] : " " );
3751 return {}; // no return value
3852 } else if (opcode == " ." ) {
3953 val = exec_dot (fragment);
4054 } else if (opcode == " *" ) {
4155 val = get_point (fragment[0 ]);
42- } else if (opcode == " add " ) {
56+ } else if (is_all_lowercase ( opcode) ) {
4357 val = call_bridge (opcode, fragment);
4458 } else if (true ) {
4559 NYI (opcode);
46- return {}; // stupid compiler.
4760 } else {
4861 throw std::runtime_error (" Can't resolve TestML function" );
4962 }
5063 return val.is_null () ? json::array_t {} : json::array_t {val};
5164 }
5265
66+ json Runtime::call_bridge (std::string const & name, json::array_t args) {
67+ std::vector<json> transformed;
68+ std::transform (args.begin (), args.end (), std::back_inserter (transformed),
69+ [this ](json& j) { return exec_expr (j)[0 ] /* TODO exec() */ ; });
70+ return _bridge.call (name, transformed);
71+ }
72+
5373 json Runtime::get_point (std::string const & name) {
5474 return _currentBlock[" point" ][name];
5575 }
@@ -60,11 +80,10 @@ namespace testml {
6080 for (auto call : fragment) {
6181 // add context right after the opcode
6282 call.insert (call.begin () + 1 /* after opcode */ , context.begin (), context.end ());
63- std::cout << " call: " << call << " with context " << context << std::endl;
6483 // we now have the full argument list
6584 context = exec_expr (call);
6685 }
67- return context;
86+ return context[ 0 ] ;
6887 }
6988
7089 void Runtime::each_pick (json::array_t list, json::array_t expr) {
@@ -116,6 +135,7 @@ namespace testml {
116135 for (auto & statement : _ast[" code" ]) {
117136 exec_expr (statement);
118137 }
138+ testml_done ();
119139 }
120140
121141 Runtime::~Runtime () {
0 commit comments