1 module builder;
2 
3 import std.experimental.allocator;
4 import std.experimental.allocator.mallocator : Mallocator;
5 import std.exception : enforce;
6 
7 import fixedsizearray;
8 
9 import helper;
10 import ast;
11 import parser;
12 import lexer;
13 
14 string ctor = `
15 
16 HTTPServerRequest __request;
17 HTTPServerResponse __response;
18 Document document;
19 Parser parser;
20 this(HTTPServerRequest req, HTTPServerResponse res) {
21 	this.__resquest = req;
22 	this.__response = res;
23 
24 	this.parser = Parser(Lexer(req.bodyReader.readAllUTF8()));
25 }
26 
27 void parse() {
28 	this.document = this.parser.parseDocument();
29 }
30 `;
31 
32 struct Fragment {
33 	string name;
34 	string tc;
35 	Directives dirs;
36 	Selections sels;
37 }
38 
39 FragmentDefinition findFragment(Document doc, string name) {
40 	Definitions cur = doc.defs;
41 	while(cur !is null) {
42 		enforce(cur.def !is null);
43 		if(cur.def.ruleSelection == DefinitionEnum.F) {
44 			enforce(cur.def.frag !is null);
45 			if(cur.def.frag.name.value == name) {
46 				return cur.def.frag;
47 			}
48 		}
49 		cur = cur.follow;
50 	}
51 
52 	return null;
53 }
54 
55 unittest {
56 	string s = `{
57  user(id: 1) {
58    friends {
59      name
60    }
61    name
62    age
63  }
64 }`;
65 	auto l = Lexer(s);
66 	auto p = Parser(l);
67 	auto d = p.parseDocument();
68 
69 	auto f = findFragment(d, "fooo");
70 	assert(f is null);
71 }
72 
73 unittest {
74 	string s = `
75 fragment fooo on Hero {
76   name
77 }`;
78 	auto l = Lexer(s);
79 	auto p = Parser(l);
80 	auto d = p.parseDocument();
81 
82 	auto f = findFragment(d, "fooo");
83 	assert(f !is null);
84 	assert(f.ss.sel.sel.field.name.name.value == "name");
85 }
86 
87 void resolveFragments(ref FixedSizeArray!(Selections,32) stack, Document doc) {
88 	if(stack.length == 0) {
89 		return;
90 	}
91 	if(stack.back.sel.ruleSelection == SelectionEnum.Field) {
92 		return;
93 	} else if(stack.back.sel.ruleSelection == SelectionEnum.Spread) {
94 		FragmentDefinition f = findFragment(doc, stack.back.sel.frag.name.value);
95 		enforce(f !is null);
96 
97 		Selections fs = f.ss.sel;
98 		stack.insertBack(fs);
99 		resolveFragments(stack, doc);
100 	}
101 }
102 
103 struct ArgumentRangeItem {
104 	Argument arg;
105 
106 	@property string name() const pure {
107 		return arg.name.value;
108 	}
109 
110 	@property ValueOrVariable value() {
111 		return arg.vv;
112 	}
113 }
114 
115 struct ArgumentRange {
116 	ArgumentList cur;
117 
118 	@property bool empty() const pure {
119 		return this.cur is null;
120 	}
121 
122 	@property ArgumentRangeItem front() {
123 		return ArgumentRangeItem(this.cur.arg);
124 	}
125 
126 	void popFront() {
127 		this.cur = this.cur.follow;
128 	}
129 
130 	@property ArgumentRange save() {
131 		return ArgumentRange(this.cur);
132 	}
133 }
134 
135 struct FieldRangeItem {
136 	Field f;
137 	Document doc;
138 
139 	@property string name() {
140 		return f.name.name.value;
141 	}
142 
143 	@property string aka() {
144 		return f.name.aka.value;
145 	}
146 
147 	ArgumentRange arguments() {
148 		if(this.f.args !is null) {
149 			return ArgumentRange(f.args.arg);
150 		} else {
151 			return ArgumentRange(null);
152 		}
153 	}
154 
155 	bool hasSelectionSet() pure @safe {
156 		return f.ss !is null;
157 	}
158 
159 	FieldRange selectionSet() {
160 		return FieldRange(this.f.ss.sel, this.doc);
161 	}
162 
163 }
164 
165 struct FieldRange {
166 	FixedSizeArray!(Selections,32) cur;
167 	Document doc;
168 
169 	this(Selections sels, Document doc) {
170 		this.doc = doc;
171 		this.cur.insertBack(sels);
172 		resolveFragments(this.cur, this.doc);
173 	}
174 
175 	this(ref FieldRange old) {
176 		this.cur = old.cur;
177 		this.doc = doc;
178 	}
179 
180 	@property bool empty() const pure {
181 		return this.cur.length == 0;
182 	}
183 
184 	@property FieldRangeItem front() {
185 		return FieldRangeItem(this.cur.back.sel.field, this.doc);
186 	}
187 
188 	void popFront() {
189 		while(this.cur.length > 0) {
190 			this.cur.back = this.cur.back.follow;
191 			if(this.cur.back is null) {
192 				this.cur.removeBack();
193 				continue;
194 			} else {
195 				resolveFragments(this.cur, this.doc);
196 				break;
197 			}
198 		}
199 	}
200 
201 	@property FieldRange save() {
202 		return FieldRange(this);
203 	}
204 }
205 
206 FieldRange fieldRange(OperationDefinition od, Document doc) {
207 	return FieldRange(od.accessNN!(["ss", "sel"]), doc);
208 }
209 
210 FieldRange fieldRange(SelectionSet ss, Document doc) {
211 	return FieldRange(ss.sel, doc);
212 }
213 
214 struct OpDefRangeItem {
215 	Document doc;
216 	Definition def;
217 
218 	FieldRange fieldRange() {
219 		return .fieldRange(accessNN!(["op", "ss"])(this.def), this.doc);
220 	}
221 }
222 
223 struct OpDefRange {
224 	Document doc;
225 	Definitions defs;
226 
227 	this(Document doc) {
228 		this.doc = doc;
229 		this.defs = doc.defs;
230 		this.advance();
231 	}
232 
233 	private void advance() {
234 		while(this.defs !is null 
235 				&& this.defs.def.ruleSelection != DefinitionEnum.O)
236 		{
237 			this.defs = this.defs.follow;
238 		}
239 	}
240 
241 	@property bool empty() const {
242 		return this.defs is null;
243 	}
244 
245 	@property OpDefRangeItem front() {
246 		return OpDefRangeItem(this.doc, this.defs.def);
247 	}
248 
249 	void popFront() {
250 		this.defs = this.defs.follow;
251 		this.advance();
252 	}
253 
254 	@property typeof(this) save() {
255 		OpDefRange ret;
256 		ret.doc = this.doc;
257 		ret.defs = this.defs;
258 		return ret;
259 	}
260 }
261 
262 OpDefRange opDefRange(Document doc) {
263 	return OpDefRange(doc);
264 }
265 
266 unittest {
267 	string s = `{
268  user(id: 1) {
269    friends {
270      name
271    }
272    name
273    age
274  }
275 }`;
276 	auto l = Lexer(s);
277 	auto p = Parser(l);
278 	auto d = p.parseDocument();
279 
280 	FieldRange r = fieldRange(d.defs.def.op, d);
281 	assert(!r.empty);
282 	assert(r.front.name == "user");
283 	ArgumentRange argL = r.front.arguments();
284 	assert(!argL.empty);
285 	auto ari = argL.front;
286 	assert(ari.name == "id");
287 	argL.popFront();
288 	assert(argL.empty);
289 	assert(r.front.hasSelectionSet());
290 	auto fss = r.front.selectionSet();
291 	assert(!fss.empty);
292 	assert(fss.front.name == "friends");
293 	fss.popFront();
294 	assert(!fss.empty);
295 	assert(fss.front.name == "name");
296 	fss.popFront();
297 	assert(!fss.empty);
298 	assert(fss.front.name == "age");
299 	fss.popFront();
300 	assert(fss.empty);
301 	r.popFront();
302 	assert(r.empty);
303 }
304 
305 unittest {
306 	string s = `{
307  user(id: 1) {
308 	 ...foo
309  }
310 }
311 
312 fragment foo on User {
313 	name
314 	age
315 }
316 `;
317 	auto l = Lexer(s);
318 	auto p = Parser(l);
319 	auto d = p.parseDocument();
320 
321 	auto f = findFragment(d, "foo");
322 	assert(f !is null);
323 
324 	FieldRange r = fieldRange(d.defs.def.op, d);
325 	assert(!r.empty);
326 	assert(r.front.name == "user");
327 	ArgumentRange argL = r.front.arguments();
328 	assert(!argL.empty);
329 	auto ari = argL.front;
330 	assert(ari.name == "id");
331 	argL.popFront();
332 	assert(argL.empty);
333 	assert(r.front.hasSelectionSet());
334 	auto fss = r.front.selectionSet();
335 	assert(!fss.empty);
336 	assert(fss.front.name == "name", fss.front.name);
337 	fss.popFront();
338 	assert(!fss.empty);
339 	assert(fss.front.name == "age");
340 	fss.popFront();
341 	assert(fss.empty);
342 	r.popFront();
343 	assert(r.empty);
344 }
345 
346 unittest {
347 	string s = `{
348  user(id: 1) {
349 	 ...foo
350 	 ...bar
351  }
352 }
353 
354 fragment foo on User {
355 	name
356 }
357 
358 fragment bar on User {
359 	age
360 }
361 `;
362 	auto l = Lexer(s);
363 	auto p = Parser(l);
364 	auto d = p.parseDocument();
365 
366 	auto f = findFragment(d, "foo");
367 	assert(f !is null);
368 
369 	auto f2 = findFragment(d, "bar");
370 	assert(f2 !is null);
371 
372 	FieldRange r = fieldRange(d.defs.def.op, d);
373 	assert(!r.empty);
374 	assert(r.front.name == "user");
375 	ArgumentRange argL = r.front.arguments();
376 	assert(!argL.empty);
377 	auto ari = argL.front;
378 	assert(ari.name == "id");
379 	argL.popFront();
380 	assert(argL.empty);
381 	assert(r.front.hasSelectionSet());
382 	auto fss = r.front.selectionSet();
383 	assert(!fss.empty);
384 	assert(fss.front.name == "name", fss.front.name);
385 	fss.popFront();
386 	assert(!fss.empty);
387 	assert(fss.front.name == "age");
388 	fss.popFront();
389 	assert(fss.empty);
390 	r.popFront();
391 	assert(r.empty);
392 }
393 
394 unittest {
395 	string s = `{
396  user(id: 1) {
397 	 ...foo
398 	 ...bar
399 	 hello
400  }
401 }
402 
403 fragment foo on User {
404 	name
405 }
406 
407 fragment bar on User {
408 	age
409 }
410 `;
411 	auto l = Lexer(s);
412 	auto p = Parser(l);
413 	auto d = p.parseDocument();
414 
415 	auto f = findFragment(d, "foo");
416 	assert(f !is null);
417 
418 	auto f2 = findFragment(d, "bar");
419 	assert(f2 !is null);
420 
421 	FieldRange r = fieldRange(d.defs.def.op, d);
422 	assert(!r.empty);
423 	assert(r.front.name == "user");
424 	ArgumentRange argL = r.front.arguments();
425 	assert(!argL.empty);
426 	auto ari = argL.front;
427 	assert(ari.name == "id");
428 	argL.popFront();
429 	assert(argL.empty);
430 	assert(r.front.hasSelectionSet());
431 	auto fss = r.front.selectionSet();
432 	assert(!fss.empty);
433 	assert(fss.front.name == "name", fss.front.name);
434 	fss.popFront();
435 	assert(!fss.empty);
436 	assert(fss.front.name == "age");
437 	fss.popFront();
438 	assert(!fss.empty);
439 	assert(fss.front.name == "hello");
440 	fss.popFront();
441 	assert(fss.empty);
442 	r.popFront();
443 	assert(r.empty);
444 }
445 
446 unittest {
447 	string s = `{
448  user(id: 1) {
449 	 hello
450 	 ...foo
451 	 ...bar
452  }
453 }
454 
455 fragment foo on User {
456 	name
457 }
458 
459 fragment bar on User {
460 	age
461 }
462 `;
463 	auto l = Lexer(s);
464 	auto p = Parser(l);
465 	auto d = p.parseDocument();
466 
467 	auto f = findFragment(d, "foo");
468 	assert(f !is null);
469 
470 	auto f2 = findFragment(d, "bar");
471 	assert(f2 !is null);
472 
473 	FieldRange r = fieldRange(d.defs.def.op, d);
474 	assert(!r.empty);
475 	assert(r.front.name == "user");
476 	ArgumentRange argL = r.front.arguments();
477 	assert(!argL.empty);
478 	auto ari = argL.front;
479 	assert(ari.name == "id");
480 	argL.popFront();
481 	assert(argL.empty);
482 	assert(r.front.hasSelectionSet());
483 	auto fss = r.front.selectionSet();
484 	assert(!fss.empty);
485 	assert(fss.front.name == "hello", fss.front.name);
486 	fss.popFront();
487 	assert(!fss.empty);
488 	assert(fss.front.name == "name");
489 	fss.popFront();
490 	assert(!fss.empty);
491 	assert(fss.front.name == "age");
492 	fss.popFront();
493 	assert(fss.empty);
494 	r.popFront();
495 	assert(r.empty);
496 }
497 
498 unittest {
499 	string s = `{
500  user(id: 1) {
501 	 hello
502 	 ...foo
503 	 ...bar
504  }
505 }
506 
507 fragment foo on User {
508 	name
509 }
510 
511 fragment bar on User {
512 	age
513 	...baz
514 }
515 
516 fragment baz on User {
517 	args
518 }
519 `;
520 	auto l = Lexer(s);
521 	auto p = Parser(l);
522 	auto d = p.parseDocument();
523 
524 	auto f = findFragment(d, "foo");
525 	assert(f !is null);
526 
527 	auto f2 = findFragment(d, "bar");
528 	assert(f2 !is null);
529 
530 	FieldRange r = fieldRange(d.defs.def.op, d);
531 	assert(!r.empty);
532 	assert(r.front.name == "user");
533 	ArgumentRange argL = r.front.arguments();
534 	assert(!argL.empty);
535 	auto ari = argL.front;
536 	assert(ari.name == "id");
537 	argL.popFront();
538 	assert(argL.empty);
539 	assert(r.front.hasSelectionSet());
540 	auto fss = r.front.selectionSet();
541 	assert(!fss.empty);
542 	assert(fss.front.name == "hello", fss.front.name);
543 	fss.popFront();
544 	assert(!fss.empty);
545 	assert(fss.front.name == "name");
546 	fss.popFront();
547 	assert(!fss.empty);
548 	assert(fss.front.name == "age");
549 	fss.popFront();
550 	assert(!fss.empty);
551 	assert(fss.front.name == "args");
552 	fss.popFront();
553 	assert(fss.empty);
554 	r.popFront();
555 	assert(r.empty);
556 }
557 
558 unittest {
559 	string s = `{
560  user(id: 1) {
561 	 hello
562 	 ...foo
563 	 zzzz
564 	 ...bar
565  }
566 }
567 
568 fragment foo on User {
569 	name
570 }
571 
572 fragment bar on User {
573 	age
574 	...baz
575 }
576 
577 fragment baz on User {
578 	args
579 }
580 `;
581 	auto l = Lexer(s);
582 	auto p = Parser(l);
583 	auto d = p.parseDocument();
584 
585 	auto f = findFragment(d, "foo");
586 	assert(f !is null);
587 
588 	auto f2 = findFragment(d, "bar");
589 	assert(f2 !is null);
590 
591 	FieldRange r = fieldRange(d.defs.def.op, d);
592 	assert(!r.empty);
593 	assert(r.front.name == "user");
594 	ArgumentRange argL = r.front.arguments();
595 	assert(!argL.empty);
596 	auto ari = argL.front;
597 	assert(ari.name == "id");
598 	argL.popFront();
599 	assert(argL.empty);
600 	assert(r.front.hasSelectionSet());
601 	auto fss = r.front.selectionSet();
602 	assert(!fss.empty);
603 	assert(fss.front.name == "hello", fss.front.name);
604 	fss.popFront();
605 	assert(!fss.empty);
606 	assert(fss.front.name == "name");
607 	fss.popFront();
608 	assert(!fss.empty);
609 	assert(fss.front.name == "zzzz");
610 	fss.popFront();
611 	assert(!fss.empty);
612 	assert(fss.front.name == "age");
613 	fss.popFront();
614 	assert(!fss.empty);
615 	assert(fss.front.name == "args");
616 	fss.popFront();
617 	assert(fss.empty);
618 	r.popFront();
619 	assert(r.empty);
620 }
621 
622 unittest {
623 	import std.format : format;
624 	import std.stdio;
625 
626 	string s = `{
627  user(id: 1) {
628 	 hello
629 	 ...foo
630 	 zzzz
631 	 ...bar
632  }
633 }
634 
635 fragment foo on User {
636 	name
637 }
638 
639 fragment bar on User {
640 	age
641 	...baz
642 }
643 
644 fragment baz on User {
645 	args
646 }
647 `;
648 	auto l = Lexer(s);
649 	auto p = Parser(l);
650 	auto d = p.parseDocument();
651 
652 	auto nn = ["hello", "name", "zzzz", "age", "args"];
653 	size_t cnt = 0;
654 	foreach(it; opDefRange(d)) {
655 		++cnt;
656 		long idx;
657 		foreach(jt; it.fieldRange()) {
658 			writef("%s(", jt.name);
659 			foreach(var; jt.arguments()) {
660 				writef("%s, ", var.name());
661 			}
662 			writeln(")");
663 			foreach(kt; jt.selectionSet()) {
664 				writeln("\t", kt.name);
665 				assert(kt.name == nn[idx], 
666 						format("%s == %d(%s)", kt.name, idx, nn[idx])
667 					);
668 				++idx;
669 			}
670 		}
671 	}
672 	assert(cnt == 1);
673 }