Skip to content

Commit b8df491

Browse files
committed
support for storing white space and comments in the AST
1 parent 765bc10 commit b8df491

File tree

1 file changed

+95
-57
lines changed

1 file changed

+95
-57
lines changed

lib/webidl2.js

Lines changed: 95 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
return tokens;
3232
};
3333

34-
var parse = function (tokens) {
34+
var parse = function (tokens, opt) {
3535
var line = 1;
3636
tokens = tokens.slice();
3737

@@ -82,14 +82,41 @@
8282
}
8383
};
8484

85-
var all_ws = function () {
85+
var all_ws = function (store) {
8686
var t = { type: "whitespace", value: "" };
8787
while (true) {
8888
var w = ws();
8989
if (!w) break;
9090
t.value += w.value;
9191
}
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+
}
93120
};
94121

95122
var integer_type = function () {
@@ -218,9 +245,9 @@
218245
return single_type() || union_type();
219246
};
220247

221-
var argument = function () {
248+
var argument = function (store) {
222249
var ret = { optional: false, variadic: false };
223-
ret.extAttrs = extended_attrs();
250+
ret.extAttrs = extended_attrs(store);
224251
all_ws();
225252
if (consume(ID, "optional")) {
226253
ret.optional = true;
@@ -251,19 +278,21 @@
251278
return ret;
252279
};
253280

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+
;
256285
if (!arg) return ret;
257286
ret.push(arg);
258287
while (true) {
259-
all_ws();
288+
all_ws(store ? ret : null);
260289
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");
262291
ret.push(nxt);
263292
}
264293
};
265294

266-
var simple_extended_attr = function () {
295+
var simple_extended_attr = function (store) {
267296
all_ws();
268297
var name = consume(ID);
269298
if (!name) return;
@@ -280,7 +309,7 @@
280309
}
281310
all_ws();
282311
if (consume(OTHER, "(")) {
283-
ret["arguments"] = argument_list();
312+
ret["arguments"] = argument_list(store);
284313
all_ws();
285314
consume(OTHER, ")") || error("Unclosed argument in extended attribute");
286315
}
@@ -289,14 +318,14 @@
289318

290319
// Note: we parse something simpler than the official syntax. It's all that ever
291320
// seems to be used
292-
var extended_attrs = function () {
321+
var extended_attrs = function (store) {
293322
var eas = [];
294-
all_ws();
323+
all_ws(store);
295324
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");
297326
all_ws();
298327
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"));
300329
all_ws();
301330
}
302331
consume(OTHER, "]") || error("No end of extended attribute");
@@ -357,22 +386,22 @@
357386
}
358387
};
359388

360-
var operation_rest = function (ret) {
389+
var operation_rest = function (ret, store) {
361390
all_ws();
362391
if (!ret) ret = {};
363392
var name = consume(ID);
364393
ret.name = name ? name.value : null;
365394
all_ws();
366395
consume(OTHER, "(") || error("Invalid operation");
367-
ret["arguments"] = argument_list();
396+
ret["arguments"] = argument_list(store);
368397
all_ws();
369398
consume(OTHER, ")") || error("Unterminated operation");
370399
all_ws();
371400
consume(OTHER, ";") || error("Unterminated operation");
372401
return ret;
373402
};
374403

375-
var callback = function () {
404+
var callback = function (store) {
376405
all_ws();
377406
var ret;
378407
if (!consume(ID, "callback")) return;
@@ -392,7 +421,7 @@
392421
ret.idlType = return_type();
393422
all_ws();
394423
consume(OTHER, "(") || error("No arguments in callback");
395-
ret["arguments"] = argument_list();
424+
ret["arguments"] = argument_list(store);
396425
all_ws();
397426
consume(OTHER, ")") || error("Unterminated callback");
398427
all_ws();
@@ -459,7 +488,7 @@
459488
return typ;
460489
};
461490

462-
var operation = function () {
491+
var operation = function (store) {
463492
all_ws();
464493
var ret = {
465494
type: "operation"
@@ -483,21 +512,21 @@
483512
if (ret.getter || ret.setter || ret.creator || ret.deleter || ret.legacycaller) {
484513
all_ws();
485514
ret.idlType = return_type();
486-
operation_rest(ret);
515+
operation_rest(ret, store);
487516
return ret;
488517
}
489518
if (consume(ID, "static")) {
490519
ret["static"] = true;
491520
ret.idlType = return_type();
492-
operation_rest(ret);
521+
operation_rest(ret, store);
493522
return ret;
494523
}
495524
else if (consume(ID, "stringifier")) {
496525
ret.stringifier = true;
497526
all_ws();
498527
if (consume(OTHER, ";")) return ret;
499528
ret.idlType = return_type();
500-
operation_rest(ret);
529+
operation_rest(ret, store);
501530
return ret;
502531
}
503532
ret.idlType = return_type();
@@ -518,7 +547,7 @@
518547
return ret;
519548
}
520549
else {
521-
operation_rest(ret);
550+
operation_rest(ret, store);
522551
return ret;
523552
}
524553
};
@@ -535,7 +564,7 @@
535564
}
536565
};
537566

538-
var serialiser = function () {
567+
var serialiser = function (store) {
539568
all_ws();
540569
if (!consume(ID, "serializer")) return;
541570
var ret = { type: "serializer" };
@@ -594,76 +623,83 @@
594623
else {
595624
ret.idlType = return_type();
596625
all_ws();
597-
ret.operation = operation_rest();
626+
ret.operation = operation_rest(null, store);
598627
}
599628
return ret;
600629
};
601630

602-
var interface_ = function (isPartial) {
631+
var interface_ = function (isPartial, store) {
603632
all_ws();
604633
if (!consume(ID, "interface")) return;
605634
all_ws();
606635
var name = consume(ID) || error("No name for interface");
607-
var ret = {
636+
var mems = []
637+
, ret = {
608638
type: "interface"
609639
, name: name.value
610640
, partial: false
611-
, members: []
641+
, members: mems
612642
};
613643
if (!isPartial) ret.inheritance = inheritance() || null;
614644
all_ws();
615645
consume(OTHER, "{") || error("Bodyless interface");
616646
while (true) {
617-
all_ws();
647+
all_ws(store ? mems : null);
618648
if (consume(OTHER, "}")) {
619649
all_ws();
620650
consume(OTHER, ";") || error("Missing semicolon after interface");
621651
return ret;
622652
}
623-
var ea = extended_attrs();
653+
var ea = extended_attrs(store ? mems : null);
624654
all_ws();
625655
var cnt = const_();
626656
if (cnt) {
627657
cnt.extAttrs = ea;
628658
ret.members.push(cnt);
629659
continue;
630660
}
631-
var mem = serialiser() || attribute() || operation() || error("Unknown member");
661+
var mem = serialiser(store) ||
662+
attribute() ||
663+
operation(store) ||
664+
error("Unknown member");
632665
mem.extAttrs = ea;
633666
ret.members.push(mem);
634667
}
635668
};
636669

637-
var partial = function () {
670+
var partial = function (store) {
638671
all_ws();
639672
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");
641676
thing.partial = true;
642677
return thing;
643678
};
644679

645-
var dictionary = function (isPartial) {
680+
var dictionary = function (isPartial, store) {
646681
all_ws();
647682
if (!consume(ID, "dictionary")) return;
648683
all_ws();
649684
var name = consume(ID) || error("No name for dictionary");
650-
var ret = {
685+
var mems = []
686+
, ret = {
651687
type: "dictionary"
652688
, name: name.value
653689
, partial: false
654-
, members: []
690+
, members: mems
655691
};
656692
if (!isPartial) ret.inheritance = inheritance() || null;
657693
all_ws();
658694
consume(OTHER, "{") || error("Bodyless dictionary");
659695
while (true) {
660-
all_ws();
696+
all_ws(store ? mems : null);
661697
if (consume(OTHER, "}")) {
662698
all_ws();
663699
consume(OTHER, ";") || error("Missing semicolon after dictionary");
664700
return ret;
665701
}
666-
var ea = extended_attrs();
702+
var ea = extended_attrs(store ? mems : null);
667703
all_ws();
668704
var typ = type() || error("No type for dictionary member");
669705
all_ws();
@@ -680,12 +716,13 @@
680716
}
681717
};
682718

683-
var exception = function () {
719+
var exception = function (store) {
684720
all_ws();
685721
if (!consume(ID, "exception")) return;
686722
all_ws();
687723
var name = consume(ID) || error("No name for exception");
688-
var ret = {
724+
var mems = true
725+
, ret = {
689726
type: "exception"
690727
, name: name.value
691728
, members: []
@@ -694,13 +731,13 @@
694731
all_ws();
695732
consume(OTHER, "{") || error("Bodyless exception");
696733
while (true) {
697-
all_ws();
734+
all_ws(store ? mems : null);
698735
if (consume(OTHER, "}")) {
699736
all_ws();
700737
consume(OTHER, ";") || error("Missing semicolon after exception");
701738
return ret;
702739
}
703-
var ea = extended_attrs();
740+
var ea = extended_attrs(store ? mems : null);
704741
all_ws();
705742
var cnt = const_();
706743
if (cnt) {
@@ -799,24 +836,24 @@
799836
}
800837
};
801838

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() ||
810847
implements_()
811848
;
812849
};
813850

814-
var definitions = function () {
851+
var definitions = function (store) {
815852
if (!tokens.length) return [];
816853
var defs = [];
817854
while (true) {
818-
var ea = extended_attrs()
819-
, def = definition();
855+
var ea = extended_attrs(store ? defs : null)
856+
, def = definition(store ? defs : null);
820857
if (!def) {
821858
if (ea.length) error("Stray extended attributes");
822859
break;
@@ -826,16 +863,17 @@
826863
}
827864
return defs;
828865
};
829-
var res = definitions();
866+
var res = definitions(opt.ws);
830867
if (tokens.length) error("Unrecognised tokens");
831868
return res;
832869
};
833870

834871
var inNode = typeof module !== "undefined" && module.exports
835872
, obj = {
836-
parse: function (str) {
873+
parse: function (str, opt) {
874+
if (!opt) opt = {};
837875
var tokens = tokenise(str);
838-
return parse(tokens);
876+
return parse(tokens, opt);
839877
}
840878
};
841879

0 commit comments

Comments
 (0)