|
31 | 31 | return tokens;
|
32 | 32 | };
|
33 | 33 |
|
34 |
| - var parse = function (tokens) { |
| 34 | + var parse = function (tokens, opt) { |
35 | 35 | var line = 1;
|
36 | 36 | tokens = tokens.slice();
|
37 | 37 |
|
|
82 | 82 | }
|
83 | 83 | };
|
84 | 84 |
|
85 |
| - var all_ws = function () { |
| 85 | + var all_ws = function (store) { |
86 | 86 | var t = { type: "whitespace", value: "" };
|
87 | 87 | while (true) {
|
88 | 88 | var w = ws();
|
89 | 89 | if (!w) break;
|
90 | 90 | t.value += w.value;
|
91 | 91 | }
|
92 |
| - if (t.value.length > 0) return t; |
| 92 | + if (t.value.length > 0) { |
| 93 | + if (store) { |
| 94 | + var w = t.value |
| 95 | + , re = { |
| 96 | + "ws": /^([\t\n\r ]+)/ |
| 97 | + , "line-comment": /^\/\/(.*)$/m |
| 98 | + , "multiline-comment": /^\/\*((?:.|\n|\r)*?)\*\// |
| 99 | + } |
| 100 | + , wsTypes = [] |
| 101 | + ; |
| 102 | + for (var k in re) wsTypes.push(k); |
| 103 | + while (w.length) { |
| 104 | + var matched = false; |
| 105 | + for (var i = 0, n = wsTypes.length; i < n; i++) { |
| 106 | + var type = wsTypes[i]; |
| 107 | + w = w.replace(re[type], function (tok, m1) { |
| 108 | + store.push({ type: type, value: m1 }); |
| 109 | + matched = true; |
| 110 | + return ""; |
| 111 | + }); |
| 112 | + if (matched) break; |
| 113 | + } |
| 114 | + if (matched) continue; |
| 115 | + throw new Error("Surprising white space construct."); // this shouldn't happen |
| 116 | + } |
| 117 | + } |
| 118 | + return t; |
| 119 | + } |
93 | 120 | };
|
94 | 121 |
|
95 | 122 | var integer_type = function () {
|
|
218 | 245 | return single_type() || union_type();
|
219 | 246 | };
|
220 | 247 |
|
221 |
| - var argument = function () { |
| 248 | + var argument = function (store) { |
222 | 249 | var ret = { optional: false, variadic: false };
|
223 |
| - ret.extAttrs = extended_attrs(); |
| 250 | + ret.extAttrs = extended_attrs(store); |
224 | 251 | all_ws();
|
225 | 252 | if (consume(ID, "optional")) {
|
226 | 253 | ret.optional = true;
|
|
251 | 278 | return ret;
|
252 | 279 | };
|
253 | 280 |
|
254 |
| - var argument_list = function () { |
255 |
| - var arg = argument(), ret = []; |
| 281 | + var argument_list = function (store) { |
| 282 | + var ret = [] |
| 283 | + , arg = argument(store ? ret : null) |
| 284 | + ; |
256 | 285 | if (!arg) return ret;
|
257 | 286 | ret.push(arg);
|
258 | 287 | while (true) {
|
259 |
| - all_ws(); |
| 288 | + all_ws(store ? ret : null); |
260 | 289 | if (!consume(OTHER, ",")) return ret;
|
261 |
| - var nxt = argument() || error("Trailing comma in arguments list"); |
| 290 | + var nxt = argument(store ? ret : null) || error("Trailing comma in arguments list"); |
262 | 291 | ret.push(nxt);
|
263 | 292 | }
|
264 | 293 | };
|
265 | 294 |
|
266 |
| - var simple_extended_attr = function () { |
| 295 | + var simple_extended_attr = function (store) { |
267 | 296 | all_ws();
|
268 | 297 | var name = consume(ID);
|
269 | 298 | if (!name) return;
|
|
280 | 309 | }
|
281 | 310 | all_ws();
|
282 | 311 | if (consume(OTHER, "(")) {
|
283 |
| - ret["arguments"] = argument_list(); |
| 312 | + ret["arguments"] = argument_list(store); |
284 | 313 | all_ws();
|
285 | 314 | consume(OTHER, ")") || error("Unclosed argument in extended attribute");
|
286 | 315 | }
|
|
289 | 318 |
|
290 | 319 | // Note: we parse something simpler than the official syntax. It's all that ever
|
291 | 320 | // seems to be used
|
292 |
| - var extended_attrs = function () { |
| 321 | + var extended_attrs = function (store) { |
293 | 322 | var eas = [];
|
294 |
| - all_ws(); |
| 323 | + all_ws(store); |
295 | 324 | if (!consume(OTHER, "[")) return eas;
|
296 |
| - eas[0] = simple_extended_attr() || error("Extended attribute with not content"); |
| 325 | + eas[0] = simple_extended_attr(store) || error("Extended attribute with not content"); |
297 | 326 | all_ws();
|
298 | 327 | while (consume(OTHER, ",")) {
|
299 |
| - eas.push(simple_extended_attr() || error("Trailing comma in extended attribute")); |
| 328 | + eas.push(simple_extended_attr(store) || error("Trailing comma in extended attribute")); |
300 | 329 | all_ws();
|
301 | 330 | }
|
302 | 331 | consume(OTHER, "]") || error("No end of extended attribute");
|
|
357 | 386 | }
|
358 | 387 | };
|
359 | 388 |
|
360 |
| - var operation_rest = function (ret) { |
| 389 | + var operation_rest = function (ret, store) { |
361 | 390 | all_ws();
|
362 | 391 | if (!ret) ret = {};
|
363 | 392 | var name = consume(ID);
|
364 | 393 | ret.name = name ? name.value : null;
|
365 | 394 | all_ws();
|
366 | 395 | consume(OTHER, "(") || error("Invalid operation");
|
367 |
| - ret["arguments"] = argument_list(); |
| 396 | + ret["arguments"] = argument_list(store); |
368 | 397 | all_ws();
|
369 | 398 | consume(OTHER, ")") || error("Unterminated operation");
|
370 | 399 | all_ws();
|
371 | 400 | consume(OTHER, ";") || error("Unterminated operation");
|
372 | 401 | return ret;
|
373 | 402 | };
|
374 | 403 |
|
375 |
| - var callback = function () { |
| 404 | + var callback = function (store) { |
376 | 405 | all_ws();
|
377 | 406 | var ret;
|
378 | 407 | if (!consume(ID, "callback")) return;
|
|
392 | 421 | ret.idlType = return_type();
|
393 | 422 | all_ws();
|
394 | 423 | consume(OTHER, "(") || error("No arguments in callback");
|
395 |
| - ret["arguments"] = argument_list(); |
| 424 | + ret["arguments"] = argument_list(store); |
396 | 425 | all_ws();
|
397 | 426 | consume(OTHER, ")") || error("Unterminated callback");
|
398 | 427 | all_ws();
|
|
459 | 488 | return typ;
|
460 | 489 | };
|
461 | 490 |
|
462 |
| - var operation = function () { |
| 491 | + var operation = function (store) { |
463 | 492 | all_ws();
|
464 | 493 | var ret = {
|
465 | 494 | type: "operation"
|
|
483 | 512 | if (ret.getter || ret.setter || ret.creator || ret.deleter || ret.legacycaller) {
|
484 | 513 | all_ws();
|
485 | 514 | ret.idlType = return_type();
|
486 |
| - operation_rest(ret); |
| 515 | + operation_rest(ret, store); |
487 | 516 | return ret;
|
488 | 517 | }
|
489 | 518 | if (consume(ID, "static")) {
|
490 | 519 | ret["static"] = true;
|
491 | 520 | ret.idlType = return_type();
|
492 |
| - operation_rest(ret); |
| 521 | + operation_rest(ret, store); |
493 | 522 | return ret;
|
494 | 523 | }
|
495 | 524 | else if (consume(ID, "stringifier")) {
|
496 | 525 | ret.stringifier = true;
|
497 | 526 | all_ws();
|
498 | 527 | if (consume(OTHER, ";")) return ret;
|
499 | 528 | ret.idlType = return_type();
|
500 |
| - operation_rest(ret); |
| 529 | + operation_rest(ret, store); |
501 | 530 | return ret;
|
502 | 531 | }
|
503 | 532 | ret.idlType = return_type();
|
|
518 | 547 | return ret;
|
519 | 548 | }
|
520 | 549 | else {
|
521 |
| - operation_rest(ret); |
| 550 | + operation_rest(ret, store); |
522 | 551 | return ret;
|
523 | 552 | }
|
524 | 553 | };
|
|
535 | 564 | }
|
536 | 565 | };
|
537 | 566 |
|
538 |
| - var serialiser = function () { |
| 567 | + var serialiser = function (store) { |
539 | 568 | all_ws();
|
540 | 569 | if (!consume(ID, "serializer")) return;
|
541 | 570 | var ret = { type: "serializer" };
|
|
594 | 623 | else {
|
595 | 624 | ret.idlType = return_type();
|
596 | 625 | all_ws();
|
597 |
| - ret.operation = operation_rest(); |
| 626 | + ret.operation = operation_rest(null, store); |
598 | 627 | }
|
599 | 628 | return ret;
|
600 | 629 | };
|
601 | 630 |
|
602 |
| - var interface_ = function (isPartial) { |
| 631 | + var interface_ = function (isPartial, store) { |
603 | 632 | all_ws();
|
604 | 633 | if (!consume(ID, "interface")) return;
|
605 | 634 | all_ws();
|
606 | 635 | var name = consume(ID) || error("No name for interface");
|
607 |
| - var ret = { |
| 636 | + var mems = [] |
| 637 | + , ret = { |
608 | 638 | type: "interface"
|
609 | 639 | , name: name.value
|
610 | 640 | , partial: false
|
611 |
| - , members: [] |
| 641 | + , members: mems |
612 | 642 | };
|
613 | 643 | if (!isPartial) ret.inheritance = inheritance() || null;
|
614 | 644 | all_ws();
|
615 | 645 | consume(OTHER, "{") || error("Bodyless interface");
|
616 | 646 | while (true) {
|
617 |
| - all_ws(); |
| 647 | + all_ws(store ? mems : null); |
618 | 648 | if (consume(OTHER, "}")) {
|
619 | 649 | all_ws();
|
620 | 650 | consume(OTHER, ";") || error("Missing semicolon after interface");
|
621 | 651 | return ret;
|
622 | 652 | }
|
623 |
| - var ea = extended_attrs(); |
| 653 | + var ea = extended_attrs(store ? mems : null); |
624 | 654 | all_ws();
|
625 | 655 | var cnt = const_();
|
626 | 656 | if (cnt) {
|
627 | 657 | cnt.extAttrs = ea;
|
628 | 658 | ret.members.push(cnt);
|
629 | 659 | continue;
|
630 | 660 | }
|
631 |
| - var mem = serialiser() || attribute() || operation() || error("Unknown member"); |
| 661 | + var mem = serialiser(store) || |
| 662 | + attribute() || |
| 663 | + operation(store) || |
| 664 | + error("Unknown member"); |
632 | 665 | mem.extAttrs = ea;
|
633 | 666 | ret.members.push(mem);
|
634 | 667 | }
|
635 | 668 | };
|
636 | 669 |
|
637 |
| - var partial = function () { |
| 670 | + var partial = function (store) { |
638 | 671 | all_ws();
|
639 | 672 | if (!consume(ID, "partial")) return;
|
640 |
| - var thing = dictionary(true) || interface_(true) || error("Partial doesn't apply to anything"); |
| 673 | + var thing = dictionary(true, store) || |
| 674 | + interface_(true, store) || |
| 675 | + error("Partial doesn't apply to anything"); |
641 | 676 | thing.partial = true;
|
642 | 677 | return thing;
|
643 | 678 | };
|
644 | 679 |
|
645 |
| - var dictionary = function (isPartial) { |
| 680 | + var dictionary = function (isPartial, store) { |
646 | 681 | all_ws();
|
647 | 682 | if (!consume(ID, "dictionary")) return;
|
648 | 683 | all_ws();
|
649 | 684 | var name = consume(ID) || error("No name for dictionary");
|
650 |
| - var ret = { |
| 685 | + var mems = [] |
| 686 | + , ret = { |
651 | 687 | type: "dictionary"
|
652 | 688 | , name: name.value
|
653 | 689 | , partial: false
|
654 |
| - , members: [] |
| 690 | + , members: mems |
655 | 691 | };
|
656 | 692 | if (!isPartial) ret.inheritance = inheritance() || null;
|
657 | 693 | all_ws();
|
658 | 694 | consume(OTHER, "{") || error("Bodyless dictionary");
|
659 | 695 | while (true) {
|
660 |
| - all_ws(); |
| 696 | + all_ws(store ? mems : null); |
661 | 697 | if (consume(OTHER, "}")) {
|
662 | 698 | all_ws();
|
663 | 699 | consume(OTHER, ";") || error("Missing semicolon after dictionary");
|
664 | 700 | return ret;
|
665 | 701 | }
|
666 |
| - var ea = extended_attrs(); |
| 702 | + var ea = extended_attrs(store ? mems : null); |
667 | 703 | all_ws();
|
668 | 704 | var typ = type() || error("No type for dictionary member");
|
669 | 705 | all_ws();
|
|
680 | 716 | }
|
681 | 717 | };
|
682 | 718 |
|
683 |
| - var exception = function () { |
| 719 | + var exception = function (store) { |
684 | 720 | all_ws();
|
685 | 721 | if (!consume(ID, "exception")) return;
|
686 | 722 | all_ws();
|
687 | 723 | var name = consume(ID) || error("No name for exception");
|
688 |
| - var ret = { |
| 724 | + var mems = true |
| 725 | + , ret = { |
689 | 726 | type: "exception"
|
690 | 727 | , name: name.value
|
691 | 728 | , members: []
|
|
694 | 731 | all_ws();
|
695 | 732 | consume(OTHER, "{") || error("Bodyless exception");
|
696 | 733 | while (true) {
|
697 |
| - all_ws(); |
| 734 | + all_ws(store ? mems : null); |
698 | 735 | if (consume(OTHER, "}")) {
|
699 | 736 | all_ws();
|
700 | 737 | consume(OTHER, ";") || error("Missing semicolon after exception");
|
701 | 738 | return ret;
|
702 | 739 | }
|
703 |
| - var ea = extended_attrs(); |
| 740 | + var ea = extended_attrs(store ? mems : null); |
704 | 741 | all_ws();
|
705 | 742 | var cnt = const_();
|
706 | 743 | if (cnt) {
|
|
799 | 836 | }
|
800 | 837 | };
|
801 | 838 |
|
802 |
| - var definition = function () { |
803 |
| - return callback() || |
804 |
| - interface_() || |
805 |
| - partial() || |
806 |
| - dictionary() || |
807 |
| - exception() || |
808 |
| - enum_() || |
809 |
| - typedef() || |
| 839 | + var definition = function (store) { |
| 840 | + return callback(store) || |
| 841 | + interface_(false, store) || |
| 842 | + partial(store) || |
| 843 | + dictionary(store) || |
| 844 | + exception(store) || |
| 845 | + enum_() || |
| 846 | + typedef() || |
810 | 847 | implements_()
|
811 | 848 | ;
|
812 | 849 | };
|
813 | 850 |
|
814 |
| - var definitions = function () { |
| 851 | + var definitions = function (store) { |
815 | 852 | if (!tokens.length) return [];
|
816 | 853 | var defs = [];
|
817 | 854 | while (true) {
|
818 |
| - var ea = extended_attrs() |
819 |
| - , def = definition(); |
| 855 | + var ea = extended_attrs(store ? defs : null) |
| 856 | + , def = definition(store ? defs : null); |
820 | 857 | if (!def) {
|
821 | 858 | if (ea.length) error("Stray extended attributes");
|
822 | 859 | break;
|
|
826 | 863 | }
|
827 | 864 | return defs;
|
828 | 865 | };
|
829 |
| - var res = definitions(); |
| 866 | + var res = definitions(opt.ws); |
830 | 867 | if (tokens.length) error("Unrecognised tokens");
|
831 | 868 | return res;
|
832 | 869 | };
|
833 | 870 |
|
834 | 871 | var inNode = typeof module !== "undefined" && module.exports
|
835 | 872 | , obj = {
|
836 |
| - parse: function (str) { |
| 873 | + parse: function (str, opt) { |
| 874 | + if (!opt) opt = {}; |
837 | 875 | var tokens = tokenise(str);
|
838 |
| - return parse(tokens); |
| 876 | + return parse(tokens, opt); |
839 | 877 | }
|
840 | 878 | };
|
841 | 879 |
|
|
0 commit comments