1
1
#include < string>
2
+ #include < iterator>
2
3
#include < iomanip> // TODO remove
3
4
#include < fstream>
4
5
#include < stdexcept>
5
6
#include < iostream>
7
+ #include < functional>
8
+
6
9
#include " runtime.hpp"
10
+ #include " bridge.hpp"
7
11
8
- static void NYI (std::string const & add = " " ) {
12
+ [[noreturn]] static void NYI (std::string const & add = " " ) {
9
13
throw std::runtime_error (" Not Yet Implemented, sorry! " + add);
10
14
}
11
15
12
16
using json = nlohmann::json;
13
17
14
18
namespace testml {
15
19
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
+
17
29
std::ifstream stream (filename);
18
30
stream >> _ast;
19
31
20
32
_data = _ast[" data" ];
21
33
}
22
34
23
- json Runtime::exec_expr (json:: array_t fragment) {
35
+ json Runtime::exec_expr (json fragment) {
24
36
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
26
40
27
- auto opcode = fragment[0 ];
41
+ std::string opcode = fragment[0 ];
28
42
fragment.erase (fragment.begin ()); // pop first arg
29
43
json val;
30
44
if (opcode == " %<>" ) {
@@ -33,23 +47,29 @@ namespace testml {
33
47
each_pick (fragment[0 ], fragment[1 ]);
34
48
return {}; // no return value
35
49
} 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 ] : " " );
37
51
return {}; // no return value
38
52
} else if (opcode == " ." ) {
39
53
val = exec_dot (fragment);
40
54
} else if (opcode == " *" ) {
41
55
val = get_point (fragment[0 ]);
42
- } else if (opcode == " add " ) {
56
+ } else if (is_all_lowercase ( opcode) ) {
43
57
val = call_bridge (opcode, fragment);
44
58
} else if (true ) {
45
59
NYI (opcode);
46
- return {}; // stupid compiler.
47
60
} else {
48
61
throw std::runtime_error (" Can't resolve TestML function" );
49
62
}
50
63
return val.is_null () ? json::array_t {} : json::array_t {val};
51
64
}
52
65
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
+
53
73
json Runtime::get_point (std::string const & name) {
54
74
return _currentBlock[" point" ][name];
55
75
}
@@ -60,11 +80,10 @@ namespace testml {
60
80
for (auto call : fragment) {
61
81
// add context right after the opcode
62
82
call.insert (call.begin () + 1 /* after opcode */ , context.begin (), context.end ());
63
- std::cout << " call: " << call << " with context " << context << std::endl;
64
83
// we now have the full argument list
65
84
context = exec_expr (call);
66
85
}
67
- return context;
86
+ return context[ 0 ] ;
68
87
}
69
88
70
89
void Runtime::each_pick (json::array_t list, json::array_t expr) {
@@ -116,6 +135,7 @@ namespace testml {
116
135
for (auto & statement : _ast[" code" ]) {
117
136
exec_expr (statement);
118
137
}
138
+ testml_done ();
119
139
}
120
140
121
141
Runtime::~Runtime () {
0 commit comments