Skip to content

Commit 0629430

Browse files
committed
WIP C++ impl
1 parent afeda6a commit 0629430

File tree

9 files changed

+228
-56
lines changed

9 files changed

+228
-56
lines changed

src/cpp/bin/testml-cpp-tap

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,10 @@ testml-run-file() {
1515
set -x
1616
/usr/bin/env c++ \
1717
-o $testml_runner \
18+
-std=c++14 \
1819
$src_bin \
1920
$lib/run/tap.cpp \
20-
$lib/run.cpp \
21+
$lib/runtime.cpp \
2122
$lib/stdlib.cpp \
2223
$lib/bridge.cpp \
2324
$bridge_file || return

src/cpp/lib/testml/run.cpp

Lines changed: 0 additions & 16 deletions
This file was deleted.

src/cpp/lib/testml/run.h

Lines changed: 0 additions & 13 deletions
This file was deleted.

src/cpp/lib/testml/run/tap.cpp

Lines changed: 28 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,33 @@
1-
#include <iostream>
21
#include <string>
3-
#include "tap.h"
2+
#include <iostream>
3+
#include "tap.hpp"
4+
5+
namespace testml {
6+
namespace run {
47

5-
void TestML_Run_TAP::run(std::string file) {
6-
TestML_Run_TAP tap;
8+
void TAP::testml_eq(json want, json got, std::string const& label) {
9+
if (want == got) {
10+
tap_pass(label);
11+
} else {
12+
tap_fail(label);
13+
}
14+
}
715

8-
tap.from_file(file);
16+
void TAP::tap_pass(std::string const& label) {
17+
std::cout << "ok " << ++count;
18+
if (!label.empty()) {
19+
std::cout << " - " << label;
20+
}
21+
std::cout << "\n";
22+
}
923

10-
std::cout << "1..1" << std::endl;
11-
std::cout << "ok 1 - It worked" << std::endl;
24+
void TAP::tap_fail(std::string const& label) {
25+
std::cout << "not ok " << ++count;
26+
if (!label.empty()) {
27+
std::cout << " - " << label;
28+
}
29+
std::cout << "\n";
30+
}
31+
32+
}
1233
}

src/cpp/lib/testml/run/tap.h

Lines changed: 0 additions & 12 deletions
This file was deleted.

src/cpp/lib/testml/run/tap.hpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#pragma once
2+
3+
#include "../runtime.hpp"
4+
5+
#include <string>
6+
7+
namespace testml {
8+
namespace run {
9+
10+
class TAP : public Runtime {
11+
using json = nlohmann::json;
12+
using Runtime::Runtime;
13+
14+
protected:
15+
void testml_eq(json want, json got, std::string const& label) override;
16+
17+
private:
18+
void tap_pass(std::string const& label);
19+
void tap_fail(std::string const& label);
20+
21+
private:
22+
int count = 0;
23+
};
24+
25+
}
26+
}

src/cpp/lib/testml/runtime.cpp

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
#include <string>
2+
#include <iomanip> // TODO remove
3+
#include <fstream>
4+
#include <stdexcept>
5+
#include <iostream>
6+
#include "runtime.hpp"
7+
8+
static void NYI(std::string const& add = "") {
9+
throw std::runtime_error("Not Yet Implemented, sorry! " + add);
10+
}
11+
12+
using json = nlohmann::json;
13+
14+
namespace testml {
15+
16+
Runtime::Runtime(std::string const& filename) {
17+
std::ifstream stream(filename);
18+
stream >> _ast;
19+
20+
_data = _ast["data"];
21+
}
22+
23+
json Runtime::exec_expr(json::array_t fragment) {
24+
if (!fragment.is_array() || fragment.size() == 0)
25+
return fragment;
26+
27+
auto opcode = fragment[0];
28+
fragment.erase(fragment.begin()); // pop first arg
29+
json val;
30+
if (opcode == "%<>") {
31+
// TODO bound check
32+
// TODO std::unordered_map<std::string key, std::tuple<int arity, std::function call>>
33+
each_pick(fragment[0], fragment[1]);
34+
return {}; // no return value
35+
} else if (opcode == "==") {
36+
assert_eq(fragment[0], fragment[1], fragment.size() == 3 ? fragment[2] : "(no reason)");
37+
return {}; // no return value
38+
} else if (opcode == ".") {
39+
val = exec_dot(fragment);
40+
} else if (opcode == "*") {
41+
val = get_point(fragment[0]);
42+
} else if (opcode == "add") {
43+
val = call_bridge(opcode, fragment);
44+
} else if (true) {
45+
NYI(opcode);
46+
return {}; // stupid compiler.
47+
} else {
48+
throw std::runtime_error("Can't resolve TestML function");
49+
}
50+
return val.is_null() ? json::array_t{} : json::array_t{val};
51+
}
52+
53+
json Runtime::get_point(std::string const& name) {
54+
return _currentBlock["point"][name];
55+
}
56+
57+
json Runtime::exec_dot(json::array_t fragment) {
58+
json context = {}; // result of last call
59+
60+
for (auto call : fragment) {
61+
// add context right after the opcode
62+
call.insert(call.begin() + 1 /* after opcode */, context.begin(), context.end());
63+
std::cout << "call: " << call << " with context " << context << std::endl;
64+
// we now have the full argument list
65+
context = exec_expr(call);
66+
}
67+
return context;
68+
}
69+
70+
void Runtime::each_pick(json::array_t list, json::array_t expr) {
71+
for (auto& datum : _data) {
72+
_currentBlock = datum;
73+
// TODO block.point.ONLY
74+
75+
pick_exec(list, expr);
76+
}
77+
_currentBlock = {};
78+
}
79+
80+
void Runtime::pick_exec(json::array_t list, json::array_t expr) {
81+
// check whether we should run or not
82+
auto& points = _currentBlock["point"];
83+
for (json::string_t str : list) {
84+
if (!str.compare(0, 1, "*") && points.find(str.substr(1)) == points.end()) {
85+
return;
86+
}
87+
if (!str.compare(0, 2, "!*") && points.find(str.substr(2)) != points.end()) {
88+
return;
89+
}
90+
}
91+
92+
// if we didn't return beforehand, we're safe to run the expression
93+
if (is_function(expr)) {
94+
// exec_func
95+
NYI();
96+
} else {
97+
exec_expr(expr);
98+
}
99+
}
100+
101+
void Runtime::assert_eq(json::array_t left, json::array_t right, std::string const& label) {
102+
testml_eq(exec_expr(left), exec_expr(right), label);
103+
}
104+
105+
bool Runtime::is_function(json value) {
106+
if (!value.is_object()) {
107+
return false;
108+
}
109+
if (value.size() < 1) {
110+
return false;
111+
}
112+
return value[0].is_string() && value[0] == "=>";
113+
}
114+
115+
void Runtime::run() {
116+
for (auto& statement : _ast["code"]) {
117+
exec_expr(statement);
118+
}
119+
}
120+
121+
Runtime::~Runtime() {
122+
}
123+
124+
}

src/cpp/lib/testml/runtime.hpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#pragma once
2+
3+
#include <string>
4+
#include "../../ext/nlohmann/json.hpp"
5+
6+
namespace testml {
7+
8+
class Runtime {
9+
using json = nlohmann::json;
10+
11+
public:
12+
Runtime(std::string const& filename);
13+
virtual ~Runtime() = 0;
14+
15+
void run();
16+
17+
private:
18+
// toplevel methods
19+
void each_pick(json::array_t list, json::array_t expr);
20+
void pick_exec(json::array_t list, json::array_t expr);
21+
22+
private:
23+
// other methods
24+
json exec_expr(json::array_t fragment);
25+
json exec_dot(json::array_t fragment);
26+
json call_bridge(std::string const& name, json::array_t args);
27+
json get_point(std::string const& name);
28+
29+
private:
30+
void assert_eq(json::array_t got, json::array_t want, std::string const& label);
31+
32+
private:
33+
bool is_function(json value);
34+
35+
protected:
36+
// those methods are to be overriden by the runtime class implementing
37+
virtual void testml_eq(json want, json got, std::string const& label) = 0;
38+
39+
private:
40+
json _ast;
41+
json _data;
42+
json _currentBlock; /* TODO ptr or smth */
43+
};
44+
45+
}

src/cpp/src/testml-run.cpp

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,11 @@
11
#include <iostream>
2-
#include "../lib/testml/run/tap.h"
2+
#include "../lib/testml/run/tap.hpp"
33

44

55
int main(int argc, char* argv[]) {
66

7-
std::string file(argv[1]);
8-
// TestML_Run_TAP tap;
9-
// std::string f("asdf");
10-
11-
TestML_Run_TAP::run(file);
12-
// tap.run();
7+
testml::run::TAP tap{argv[1]};
8+
tap.run();
139

1410
return 0;
1511
}

0 commit comments

Comments
 (0)