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 }