OILS / asdl / gen_cpp_test.cc View on Github | oils.pub

406 lines, 258 significant
1#include <stdarg.h> // va_list, etc.
2#include <stdio.h>
3
4#include "_gen/asdl/examples/shared_variant.asdl.h"
5#include "_gen/asdl/examples/typed_arith.asdl.h"
6#include "_gen/asdl/examples/typed_demo.asdl.h" // has simple Sum, etc
7#include "mycpp/runtime.h"
8#include "prebuilt/asdl/runtime.mycpp.h"
9#include "vendor/greatest.h"
10
11using typed_arith_asdl::pipeline;
12
13using typed_arith_asdl::arith_expr; // variant type namespace
14using typed_arith_asdl::arith_expr_e; // variant tag type
15using typed_arith_asdl::arith_expr_t; // sum type
16
17using typed_demo_asdl::a_word;
18using typed_demo_asdl::bool_expr;
19using typed_demo_asdl::bool_expr_t;
20using typed_demo_asdl::op_array;
21using typed_demo_asdl::op_id_e;
22
23using hnode_asdl::hnode_e;
24
25void PrintTag(arith_expr_t* a) {
26 switch (a->tag()) {
27 case arith_expr_e::Const:
28 log("Const");
29 break;
30 case arith_expr_e::Var:
31 log("Var");
32 break;
33 default:
34 log("OTHER");
35 }
36 log("");
37}
38
39TEST misc_test() {
40 auto c = Alloc<arith_expr::Const>(42);
41 log("sizeof *c = %d", sizeof *c); // 16 bytes
42
43 ASSERT_EQ_FMT(42, c->i, "%d");
44 log("c->tag = %d", c->tag());
45 PrintTag(c);
46
47 auto v = Alloc<arith_expr::Var>(StrFromC("foo"));
48 log("sizeof *v = %d", sizeof *v); // 24 bytes
49
50 ASSERT(str_equals(StrFromC("foo"), v->name));
51 log("v->tag = %d", v->tag());
52 PrintTag(v);
53
54 auto u = Alloc<arith_expr::Unary>(StrFromC("-"), v);
55 log("u->op = %s", u->op->data_);
56
57 auto v1 = Alloc<arith_expr::Var>(StrFromC("v1"));
58 auto v2 = Alloc<arith_expr::Var>(StrFromC("v2"));
59 auto args = NewList<arith_expr_t*>({v1, v2});
60
61 auto f = Alloc<arith_expr::FuncCall>(StrFromC("f"), args);
62 log("f->name = %s", f->name->data_);
63
64 auto p = Alloc<pipeline>(true);
65 log("p->negated = %d", p->negated);
66
67#if 0
68 if (t->tag() == hnode_e::Leaf) {
69 hnode__Leaf* t2 = static_cast<hnode__Leaf*>(t);
70 log("%s", hnode_str(t2->tag()));
71 log("%s", color_str(t2->color));
72 log("%s", t2->s->data_);
73 }
74#endif
75
76 // NOTE: This is self-initialization!!!
77 /*
78 if (t->tag == hnode_e::Leaf) {
79 hnode__Leaf* t = static_cast<hnode__Leaf*>(t);
80 log("%s", hnode_str(t->tag));
81 log("%s", color_str(t->color));
82 log("%s", t->s->data_);
83 }
84 */
85
86 PASS();
87}
88
89using shared_variant_asdl::DoubleQuoted;
90
91using shared_variant_asdl::tok;
92using shared_variant_asdl::tok_e;
93using shared_variant_asdl::tok_t;
94using shared_variant_asdl::Token;
95
96TEST shared_variant_test() {
97 auto* dq = Alloc<DoubleQuoted>(0, Alloc<List<BigStr*>>());
98
99 shared_variant_asdl::word_part_t* wp = nullptr;
100 wp = dq; // assign to base type
101
102 log("wp->tag() %d", wp->tag());
103
104 auto* token = Alloc<Token>(0, StrFromC("hi"));
105 tok_t* tok = nullptr;
106 tok = token;
107
108 log("tok->tag() for Token = %d", tok->tag());
109
110 auto* eof = tok::Eof;
111 tok = eof;
112 log("tok->tag() for Eof = %d", tok->tag());
113
114 PASS();
115}
116
117using typed_demo_asdl::bool_expr_str;
118
119TEST pretty_print_test() {
120 // typed_demo.asdl
121
122 bool_expr_t* b = nullptr;
123 StackRoot _r1(&b);
124
125 auto w1 = Alloc<typed_demo_asdl::word>(StrFromC("left"));
126 auto w2 = Alloc<typed_demo_asdl::word>(StrFromC("right"));
127 b = Alloc<bool_expr::Binary>(w1, w2);
128
129 hnode_t* t1 = b->PrettyTree(false);
130 ASSERT_EQ_FMT(hnode_e::Record, t1->tag(), "%d");
131
132 auto f = mylib::Stdout();
133 format::HNodePrettyPrint(t1, f);
134 printf("\n");
135
136 BigStr* s = bool_expr_str(b->tag());
137 log("bool_expr_str = %s", s->data_);
138 ASSERT(str_equals0("bool_expr.Binary", s));
139
140 s = bool_expr_str(b->tag(), false);
141 ASSERT(str_equals0("Binary", s));
142
143 // typed_arith.asdl
144
145 arith_expr_t* c = nullptr;
146 arith_expr_t* big = nullptr;
147 StackRoot _r2(&c);
148 StackRoot _r3(&big);
149
150 c = Alloc<arith_expr::Const>(42);
151 hnode_t* t2 = c->PrettyTree(false);
152 ASSERT_EQ(hnode_e::Record, t2->tag());
153 format::HNodePrettyPrint(t2, f);
154 printf("\n");
155
156 big = Alloc<arith_expr::Big>(mops::BigInt(INT64_MAX));
157 hnode_t* t3 = big->PrettyTree(false);
158 ASSERT_EQ(hnode_e::Record, t3->tag());
159 format::HNodePrettyPrint(t3, f);
160 printf("\n");
161
162 auto* args =
163 NewList<arith_expr_t*>(std::initializer_list<arith_expr_t*>{c, big});
164 auto* func = Alloc<arith_expr::FuncCall>(StrFromC("myfunc"), args);
165 hnode_t* t4 = func->PrettyTree(false);
166 ASSERT_EQ(hnode_e::Record, t4->tag());
167 format::HNodePrettyPrint(t4, f);
168
169 PASS();
170}
171
172TEST dicts_test() {
173 auto m = typed_demo_asdl::Dicts::CreateNull();
174 log("m.ss = %p", m->ss);
175 log("m.ib = %p", m->ib);
176
177 m->ss = Alloc<Dict<BigStr*, BigStr*>>();
178 m->ib = Alloc<Dict<int, bool>>();
179
180 m->ss->set(StrFromC("foo"), StrFromC("bar"));
181
182 m->ib->set(42, true);
183 // note: Dict<int, bool>::get() doesn't compile because nullptr isn't valid
184 // to return. But Dict<int, bool>::index() does compile.
185 log("mm.ib[42] = %d", m->ib->at(42));
186
187 hnode_t* t = m->PrettyTree(false);
188 auto f = mylib::Stdout();
189 // fails with repr(void *)
190 // OK change the pretty printer!
191 format::HNodePrettyPrint(t, f);
192
193 PASS();
194}
195
196using typed_demo_asdl::flag_type;
197using typed_demo_asdl::flag_type__Bool;
198using typed_demo_asdl::SetToArg_;
199
200ObjHeader make_global(ObjHeader header) {
201 header.heap_tag = HeapTag::Global;
202 return header;
203}
204
205// TODO: We should always use these, rather than 'new flag_type::Bool()'
206GcGlobal<flag_type__Bool> g_ft = {make_global(flag_type__Bool::obj_header())};
207
208// Use __ style
209using typed_demo_asdl::cflow__Return;
210GcGlobal<cflow__Return> g_ret = {make_global(cflow__Return::obj_header()), {5}};
211
212int i0 = 7;
213
214// NOTE: This causes an failed assert() in the GC runtime
215#if 0
216List<int>* g_list = NewList<int>({i0, 8, 9});
217#endif
218
219// Dict<BigStr*, int> g_dict = {4, 5, 6};
220
221TEST literal_test() {
222 // Interesting, initializer list part of the constructor "runs". Otherwise
223 // this doesn't work.
224 log("g_ft.tag() = %d", g_ft.obj.tag());
225 auto ft = flag_type::Bool;
226 ASSERT_EQ(g_ft.obj.tag(), ft->tag());
227
228 log("g_ret.tag() = %d", g_ret.obj.tag());
229 log("g_ret.status = %d", g_ret.obj.status);
230 auto ret = Alloc<cflow__Return>(5);
231 ASSERT_EQ(g_ret.obj.tag(), ret->tag());
232 ASSERT_EQ(g_ret.obj.status, ret->status);
233
234#if 0
235 // Wow this works too? Is it the the constexpr interpreter, or is this code
236 // inserted before main()?
237 ASSERT_EQ(3, len(g_list));
238 ASSERT_EQ_FMT(7, g_list->at(0), "%d");
239 ASSERT_EQ_FMT(8, g_list->at(1), "%d");
240 ASSERT_EQ_FMT(9, g_list->at(2), "%d");
241#endif
242
243 PASS();
244}
245
246TEST string_defaults_test() {
247 auto st = Alloc<typed_demo_asdl::Strings>(kEmptyString, kEmptyString);
248 ASSERT_EQ(kEmptyString, st->required);
249 ASSERT_EQ(kEmptyString, st->optional);
250
251 st = typed_demo_asdl::Strings::CreateNull();
252 ASSERT_EQ(kEmptyString, st->required);
253 ASSERT_EQ(nullptr, st->optional);
254
255 st = Alloc<typed_demo_asdl::Strings>(kEmptyString, nullptr);
256 ASSERT_EQ(kEmptyString, st->required);
257 ASSERT_EQ(nullptr, st->optional);
258
259 PASS();
260}
261
262TEST list_defaults_test() {
263 auto o = op_array::CreateNull();
264 ASSERT_EQ(nullptr, o->ops);
265
266 // Empty list
267 auto o2 = op_array::CreateNull(true);
268 ASSERT_EQ(0, len(o2->ops));
269
270 PASS();
271}
272
273TEST type_id_test() {
274 log("--- TYPE ID test");
275 auto unique = Alloc<Dict<int, bool>>();
276
277 auto w1 = Alloc<typed_demo_asdl::word>(StrFromC("left"));
278 auto w2 = Alloc<typed_demo_asdl::word>(StrFromC("right"));
279
280 int type_id;
281 type_id = w1->type_id();
282 unique->set(type_id, true);
283 log("(product type) word type_id = %d", type_id);
284
285 auto b = Alloc<bool_expr::Binary>(w1, w2);
286 // constexpr function
287 auto sum_type_id = b->sum_type_id();
288 log("bool_expr sum_type_id() = %d", sum_type_id);
289
290 type_id = b->type_id();
291 unique->set(type_id, true);
292 log("bool_expr.Binary type_id() = %d", type_id);
293
294 auto a = Alloc<a_word::String>(StrFromC("foo"));
295 log("a_word sum_type_id() = %d", a->sum_type_id());
296 type_id = a->type_id();
297 unique->set(type_id, true);
298 log("a_word.String type_id() = %d", a->type_id());
299
300 // We set() 3 type IDs, they should be UNIQUE
301 ASSERT_EQ(3, len(unique));
302
303#if 0
304 auto opaque_list = Alloc<List<int>>();
305 ASSERT_EQ(kDoNotWalk, opaque_list->type_id());
306
307 auto pointer_list = Alloc<List<typed_demo_asdl::word*>>();
308 ASSERT_EQ(TypeTag::List, pointer_list->type_id());
309
310 log("sizeof(word) = %d", sizeof(typed_demo_asdl::word));
311
312 // Now test if they can be put in the same collection
313 auto to_walk = Alloc<List<Walkable*>>();
314 to_walk->append(w1);
315 to_walk->append(b);
316 to_walk->append(a);
317 to_walk->append(opaque_list);
318 to_walk->append(pointer_list);
319
320 // Crap, we need to retain the base type ...
321 // do_command_t() etc.
322 for (int i = 0; i < len(to_walk); ++i) {
323 Walkable* w = to_walk->at(i);
324 log("w %d", w->type_id());
325 }
326#endif
327}
328
329#include <unordered_map>
330
331class NodeWalker {
332 public:
333 virtual void methodA() {
334 log("Base::methodA");
335 }
336 virtual void methodB() {
337 log("Base::methodB");
338 }
339 virtual ~NodeWalker() = default;
340};
341
342class Linter : public NodeWalker {
343 public:
344 void methodA() override {
345 log("Derived::methodA");
346 }
347 void methodB() override {
348 log("Derived::methodB");
349 }
350};
351
352using typed_demo_asdl::word2;
353using typed_demo_asdl::word_part;
354using typed_demo_asdl::word_part_t;
355
356TEST walker_test() {
357 log("Walk");
358
359 // Make recursive structure
360 //
361 // [[ $([[ a ]]) ]]
362
363 auto tok = Alloc<typed_demo_asdl::Token>(StrFromC("a"), true);
364 auto parts = Alloc<List<word_part_t*>>();
365 typed_demo_asdl::word_part_t* part = tok;
366 parts->append(part);
367 auto w = Alloc<word2::Compound>(parts);
368 auto b = Alloc<bool_expr::WordTest>(w);
369
370#if 1
371 // Map from int to member function pointer
372 // Note: we don't use Dict because we don't need a GC type, and Dicts can
373 // only hold pointer-sized things, for tracing. Pointers to members may be
374 // bigger.
375 auto dispatch_table = std::unordered_map<int, void (NodeWalker::*)()>();
376
377 dispatch_table[1] = &NodeWalker::methodA;
378 dispatch_table[2] = &NodeWalker::methodB;
379#endif
380
381 PASS();
382}
383
384GREATEST_MAIN_DEFS();
385
386int main(int argc, char** argv) {
387 gHeap.Init();
388
389 GREATEST_MAIN_BEGIN();
390
391 RUN_TEST(misc_test);
392 RUN_TEST(shared_variant_test);
393 RUN_TEST(pretty_print_test);
394 RUN_TEST(dicts_test);
395 RUN_TEST(literal_test);
396 RUN_TEST(string_defaults_test);
397 RUN_TEST(list_defaults_test);
398 RUN_TEST(type_id_test);
399 RUN_TEST(walker_test);
400
401 gHeap.CleanProcessExit();
402
403 GREATEST_MAIN_END();
404
405 return 0;
406}