WebIDLParser.js 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841
  1. (function () {
  2. var tokenise = function (str) {
  3. var tokens = []
  4. , re = {
  5. "float": /^-?(([0-9]+\.[0-9]*|[0-9]*\.[0-9]+)([Ee][-+]?[0-9]+)?|[0-9]+[Ee][-+]?[0-9]+)/
  6. , "integer": /^-?(0([Xx][0-9A-Fa-f]+|[0-7]*)|[1-9][0-9]*)/
  7. , "identifier": /^[A-Z_a-z][0-9A-Z_a-z]*/
  8. , "string": /^"[^"]*"/
  9. , "whitespace": /^(?:[\t\n\r ]+|[\t\n\r ]*((\/\/.*|\/\*(.|\n|\r)*?\*\/)[\t\n\r ]*))+/
  10. , "other": /^[^\t\n\r 0-9A-Z_a-z]/
  11. }
  12. , types = []
  13. ;
  14. for (var k in re) types.push(k);
  15. while (str.length > 0) {
  16. var matched = false;
  17. for (var i = 0, n = types.length; i < n; i++) {
  18. var type = types[i];
  19. str = str.replace(re[type], function (tok) {
  20. tokens.push({ type: type, value: tok });
  21. matched = true;
  22. return "";
  23. });
  24. if (matched) break;
  25. }
  26. if (matched) continue;
  27. throw new Error("Token stream not progressing");
  28. }
  29. return tokens;
  30. };
  31. var parse = function (tokens) {
  32. var line = 1;
  33. tokens = tokens.slice();
  34. var FLOAT = "float"
  35. , INT = "integer"
  36. , ID = "identifier"
  37. , STR = "string"
  38. , OTHER = "other"
  39. ;
  40. var WebIDLParseError = function (str, line, input, tokens) {
  41. this.message = str;
  42. this.line = line;
  43. this.input = input;
  44. this.tokens = tokens;
  45. };
  46. WebIDLParseError.prototype.toString = function () {
  47. return this.message + ", line " + this.line + " (tokens: '" + this.input + "')\n" +
  48. JSON.stringify(this.tokens, null, 4);
  49. };
  50. var error = function (str) {
  51. var tok = "", numTokens = 0, maxTokens = 5;
  52. while (numTokens < maxTokens && tokens.length > numTokens) {
  53. tok += tokens[numTokens].value;
  54. numTokens++;
  55. }
  56. throw new WebIDLParseError(str, line, tok, tokens.slice(0, 5));
  57. };
  58. var last_token = null;
  59. var consume = function (type, value) {
  60. if (!tokens.length || tokens[0].type !== type) return;
  61. if (typeof value === "undefined" || tokens[0].value === value) {
  62. last_token = tokens.shift();
  63. if (type === ID) last_token.value = last_token.value.replace(/^_/, "");
  64. return last_token;
  65. }
  66. };
  67. var ws = function () {
  68. if (!tokens.length) return;
  69. if (tokens[0].type === "whitespace") {
  70. var t = tokens.shift();
  71. t.value.replace(/\n/g, function (m) { line++; return m; });
  72. return t;
  73. }
  74. };
  75. var all_ws = function () {
  76. var t = { type: "whitespace", value: "" };
  77. while (true) {
  78. var w = ws();
  79. if (!w) break;
  80. t.value += w.value;
  81. }
  82. if (t.value.length > 0) return t;
  83. };
  84. var integer_type = function () {
  85. var ret = "";
  86. all_ws();
  87. if (consume(ID, "unsigned")) ret = "unsigned ";
  88. all_ws();
  89. if (consume(ID, "short")) return ret + "short";
  90. if (consume(ID, "long")) {
  91. ret += "long";
  92. all_ws();
  93. if (consume(ID, "long")) return ret + " long";
  94. return ret;
  95. }
  96. if (ret) error("Failed to parse integer type");
  97. };
  98. var float_type = function () {
  99. var ret = "";
  100. all_ws();
  101. if (consume(ID, "unrestricted")) ret = "unrestricted ";
  102. all_ws();
  103. if (consume(ID, "float")) return ret + "float";
  104. if (consume(ID, "double")) return ret + "double";
  105. if (ret) error("Failed to parse float type");
  106. };
  107. var primitive_type = function () {
  108. var num_type = integer_type() || float_type();
  109. if (num_type) return num_type;
  110. all_ws();
  111. if (consume(ID, "boolean")) return "boolean";
  112. if (consume(ID, "byte")) return "byte";
  113. if (consume(ID, "octet")) return "octet";
  114. };
  115. var const_value = function () {
  116. if (consume(ID, "true")) return { type: "boolean", value: true };
  117. if (consume(ID, "false")) return { type: "boolean", value: false };
  118. if (consume(ID, "null")) return { type: "null" };
  119. if (consume(ID, "Infinity")) return { type: "Infinity", negative: false };
  120. if (consume(ID, "NaN")) return { type: "NaN" };
  121. var ret = consume(FLOAT) || consume(INT);
  122. if (ret) return { type: "number", value: 1 * ret.value };
  123. var tok = consume(OTHER, "-");
  124. if (tok) {
  125. if (consume(ID, "Infinity")) return { type: "Infinity", negative: true };
  126. else tokens.unshift(tok);
  127. }
  128. };
  129. var type_suffix = function (obj) {
  130. while (true) {
  131. all_ws();
  132. if (consume(OTHER, "?")) {
  133. if (obj.nullable) error("Can't nullable more than once");
  134. obj.nullable = true;
  135. }
  136. else if (consume(OTHER, "[")) {
  137. all_ws();
  138. consume(OTHER, "]") || error("Unterminated array type");
  139. if (!obj.array) obj.array = 1;
  140. else obj.array++;
  141. }
  142. else return;
  143. }
  144. };
  145. var single_type = function () {
  146. var prim = primitive_type()
  147. , ret = { sequence: false, nullable: false, array: false, union: false }
  148. ;
  149. if (prim) {
  150. ret.idlType = prim;
  151. }
  152. else if (consume(ID, "sequence")) {
  153. all_ws();
  154. if (!consume(OTHER, "<")) {
  155. ret.idlType = "sequence";
  156. }
  157. else {
  158. ret.sequence = true;
  159. ret.idlType = type() || error("Error parsing sequence type");
  160. all_ws();
  161. if (!consume(OTHER, ">")) error("Unterminated sequence");
  162. all_ws();
  163. if (consume(OTHER, "?")) ret.nullable = true;
  164. return ret;
  165. }
  166. }
  167. else {
  168. var name = consume(ID);
  169. if (!name) return;
  170. ret.idlType = name.value;
  171. }
  172. type_suffix(ret);
  173. if (ret.nullable && ret.idlType === "any") error("Type any cannot be made nullable");
  174. return ret;
  175. };
  176. var union_type = function () {
  177. all_ws();
  178. if (!consume(OTHER, "(")) return;
  179. var ret = { sequence: false, nullable: false, array: false, union: true, idlType: [] };
  180. var fst = type() || error("Union type with no content");
  181. ret.idlType.push(fst);
  182. while (true) {
  183. all_ws();
  184. if (!consume(ID, "or")) break;
  185. var typ = type() || error("No type after 'or' in union type");
  186. ret.idlType.push(typ);
  187. }
  188. if (!consume(OTHER, ")")) error("Unterminated union type");
  189. type_suffix(ret);
  190. return ret;
  191. };
  192. var type = function () {
  193. return single_type() || union_type();
  194. };
  195. var argument = function () {
  196. var ret = { optional: false, variadic: false };
  197. ret.extAttrs = extended_attrs();
  198. all_ws();
  199. if (consume(ID, "optional")) {
  200. ret.optional = true;
  201. all_ws();
  202. }
  203. ret.idlType = type();
  204. if (!ret.idlType) return;
  205. if (!ret.optional) {
  206. all_ws();
  207. if (tokens.length >= 3 &&
  208. tokens[0].type === "other" && tokens[0].value === "." &&
  209. tokens[1].type === "other" && tokens[1].value === "." &&
  210. tokens[2].type === "other" && tokens[2].value === "."
  211. ) {
  212. tokens.shift();
  213. tokens.shift();
  214. tokens.shift();
  215. ret.variadic = true;
  216. }
  217. }
  218. all_ws();
  219. var name = consume(ID) || error("No name in argument");
  220. ret.name = name.value;
  221. if (ret.optional) {
  222. all_ws();
  223. ret["default"] = default_();
  224. }
  225. return ret;
  226. };
  227. var argument_list = function () {
  228. var arg = argument(), ret = [];
  229. if (!arg) return ret;
  230. ret.push(arg);
  231. while (true) {
  232. all_ws();
  233. if (!consume(OTHER, ",")) return ret;
  234. all_ws();
  235. var nxt = argument() || error("Trailing comma in arguments list");
  236. ret.push(nxt);
  237. }
  238. };
  239. var simple_extended_attr = function () {
  240. all_ws();
  241. var name = consume(ID);
  242. if (!name) return;
  243. var ret = {
  244. name: name.value
  245. , "arguments": null
  246. };
  247. all_ws();
  248. var eq = consume(OTHER, "=");
  249. if (eq) {
  250. all_ws();
  251. ret.rhs = consume(ID);
  252. if (!ret.rhs) return error("No right hand side to extended attribute assignment");
  253. }
  254. all_ws();
  255. if (consume(OTHER, "(")) {
  256. ret["arguments"] = argument_list();
  257. all_ws();
  258. consume(OTHER, ")") || error("Unclosed argument in extended attribute");
  259. }
  260. return ret;
  261. };
  262. // Note: we parse something simpler than the official syntax. It's all that ever
  263. // seems to be used
  264. var extended_attrs = function () {
  265. var eas = [];
  266. all_ws();
  267. if (!consume(OTHER, "[")) return eas;
  268. eas[0] = simple_extended_attr() || error("Extended attribute with not content");
  269. all_ws();
  270. while (consume(OTHER, ",")) {
  271. all_ws();
  272. eas.push(simple_extended_attr() || error("Trailing comma in extended attribute"));
  273. all_ws();
  274. }
  275. consume(OTHER, "]") || error("No end of extended attribute");
  276. return eas;
  277. };
  278. var default_ = function () {
  279. all_ws();
  280. if (consume(OTHER, "=")) {
  281. all_ws();
  282. var def = const_value();
  283. if (def) {
  284. return def;
  285. }
  286. else {
  287. var str = consume(STR) || error("No value for default");
  288. str.value = str.value.replace(/^"/, "").replace(/"$/, "");
  289. return str;
  290. }
  291. }
  292. };
  293. var const_ = function () {
  294. all_ws();
  295. if (!consume(ID, "const")) return;
  296. var ret = { type: "const", nullable: false };
  297. all_ws();
  298. var typ = primitive_type();
  299. if (!typ) {
  300. typ = consume(ID) || error("No type for const");
  301. typ = typ.value;
  302. }
  303. ret.idlType = typ;
  304. all_ws();
  305. if (consume(OTHER, "?")) {
  306. ret.nullable = true;
  307. all_ws();
  308. }
  309. var name = consume(ID) || error("No name for const");
  310. ret.name = name.value;
  311. all_ws();
  312. consume(OTHER, "=") || error("No value assignment for const");
  313. all_ws();
  314. var cnt = const_value();
  315. if (cnt) ret.value = cnt;
  316. else error("No value for const");
  317. all_ws();
  318. consume(OTHER, ";") || error("Unterminated const");
  319. return ret;
  320. };
  321. var inheritance = function () {
  322. all_ws();
  323. if (consume(OTHER, ":")) {
  324. all_ws();
  325. var inh = consume(ID) || error ("No type in inheritance");
  326. return inh.value;
  327. }
  328. };
  329. var operation_rest = function (ret) {
  330. all_ws();
  331. if (!ret) ret = {};
  332. var name = consume(ID);
  333. ret.name = name ? name.value : null;
  334. all_ws();
  335. consume(OTHER, "(") || error("Invalid operation");
  336. ret["arguments"] = argument_list();
  337. all_ws();
  338. consume(OTHER, ")") || error("Unterminated operation");
  339. all_ws();
  340. consume(OTHER, ";") || error("Unterminated operation");
  341. return ret;
  342. };
  343. var callback = function () {
  344. all_ws();
  345. var ret;
  346. if (!consume(ID, "callback")) return;
  347. all_ws();
  348. var tok = consume(ID, "interface");
  349. if (tok) {
  350. tokens.unshift(tok);
  351. ret = interface_();
  352. ret.type = "callback interface";
  353. return ret;
  354. }
  355. var name = consume(ID) || error("No name for callback");
  356. ret = { type: "callback", name: name.value };
  357. all_ws();
  358. consume(OTHER, "=") || error("No assignment in callback");
  359. all_ws();
  360. ret.idlType = return_type();
  361. all_ws();
  362. consume(OTHER, "(") || error("No arguments in callback");
  363. ret["arguments"] = argument_list();
  364. all_ws();
  365. consume(OTHER, ")") || error("Unterminated callback");
  366. all_ws();
  367. consume(OTHER, ";") || error("Unterminated callback");
  368. return ret;
  369. };
  370. var attribute = function () {
  371. all_ws();
  372. var grabbed = []
  373. , ret = {
  374. type: "attribute"
  375. , "static": false
  376. , stringifier: false
  377. , inherit: false
  378. , readonly: false
  379. };
  380. if (consume(ID, "static")) {
  381. ret["static"] = true;
  382. grabbed.push(last_token);
  383. }
  384. else if (consume(ID, "stringifier")) {
  385. ret.stringifier = true;
  386. grabbed.push(last_token);
  387. }
  388. var w = all_ws();
  389. if (w) grabbed.push(w);
  390. if (consume(ID, "inherit")) {
  391. if (ret["static"] || ret.stringifier) error("Cannot have a static or stringifier inherit");
  392. ret.inherit = true;
  393. grabbed.push(last_token);
  394. var w = all_ws();
  395. if (w) grabbed.push(w);
  396. }
  397. if (consume(ID, "readonly")) {
  398. ret.readonly = true;
  399. grabbed.push(last_token);
  400. var w = all_ws();
  401. if (w) grabbed.push(w);
  402. }
  403. if (!consume(ID, "attribute")) {
  404. tokens = grabbed.concat(tokens);
  405. return;
  406. }
  407. all_ws();
  408. ret.idlType = type() || error("No type in attribute");
  409. if (ret.idlType.sequence) error("Attributes cannot accept sequence types");
  410. all_ws();
  411. var name = consume(ID) || error("No name in attribute");
  412. ret.name = name.value;
  413. all_ws();
  414. consume(OTHER, ";") || error("Unterminated attribute");
  415. return ret;
  416. };
  417. var return_type = function () {
  418. var typ = type();
  419. if (!typ) {
  420. if (consume(ID, "void")) {
  421. return "void";
  422. }
  423. else error("No return type");
  424. }
  425. return typ;
  426. };
  427. var operation = function () {
  428. all_ws();
  429. var ret = {
  430. type: "operation"
  431. , getter: false
  432. , setter: false
  433. , creator: false
  434. , deleter: false
  435. , legacycaller: false
  436. , "static": false
  437. , stringifier: false
  438. };
  439. while (true) {
  440. all_ws();
  441. if (consume(ID, "getter")) ret.getter = true;
  442. else if (consume(ID, "setter")) ret.setter = true;
  443. else if (consume(ID, "creator")) ret.creator = true;
  444. else if (consume(ID, "deleter")) ret.deleter = true;
  445. else if (consume(ID, "legacycaller")) ret.legacycaller = true;
  446. else break;
  447. }
  448. if (ret.getter || ret.setter || ret.creator || ret.deleter || ret.legacycaller) {
  449. all_ws();
  450. ret.idlType = return_type();
  451. operation_rest(ret);
  452. return ret;
  453. }
  454. if (consume(ID, "static")) {
  455. ret["static"] = true;
  456. ret.idlType = return_type();
  457. operation_rest(ret);
  458. return ret;
  459. }
  460. else if (consume(ID, "stringifier")) {
  461. ret.stringifier = true;
  462. all_ws();
  463. if (consume(OTHER, ";")) return ret;
  464. ret.idlType = return_type();
  465. operation_rest(ret);
  466. return ret;
  467. }
  468. ret.idlType = return_type();
  469. all_ws();
  470. if (consume(ID, "iterator")) {
  471. all_ws();
  472. ret.type = "iterator";
  473. if (consume(ID, "object")) {
  474. ret.iteratorObject = "object";
  475. }
  476. else if (consume(OTHER, "=")) {
  477. all_ws();
  478. var name = consume(ID) || error("No right hand side in iterator");
  479. ret.iteratorObject = name.value;
  480. }
  481. all_ws();
  482. consume(OTHER, ";") || error("Unterminated iterator");
  483. return ret;
  484. }
  485. else {
  486. operation_rest(ret);
  487. return ret;
  488. }
  489. };
  490. var identifiers = function (arr) {
  491. while (true) {
  492. all_ws();
  493. if (consume(OTHER, ",")) {
  494. all_ws();
  495. var name = consume(ID) || error("Trailing comma in identifiers list");
  496. arr.push(name.value);
  497. }
  498. else break;
  499. }
  500. };
  501. var serialiser = function () {
  502. all_ws();
  503. if (!consume(ID, "serializer")) return;
  504. var ret = { type: "serializer" };
  505. all_ws();
  506. if (consume(OTHER, "=")) {
  507. all_ws();
  508. if (consume(OTHER, "{")) {
  509. ret.patternMap = true;
  510. all_ws();
  511. var id = consume(ID);
  512. if (id && id.value === "getter") {
  513. ret.names = ["getter"];
  514. }
  515. else if (id && id.value === "inherit") {
  516. ret.names = ["inherit"];
  517. identifiers(ret.names);
  518. }
  519. else if (id) {
  520. ret.names = [id.value];
  521. identifiers(ret.names);
  522. }
  523. else {
  524. ret.names = [];
  525. }
  526. all_ws();
  527. consume(OTHER, "}") || error("Unterminated serializer pattern map");
  528. }
  529. else if (consume(OTHER, "[")) {
  530. ret.patternList = true;
  531. all_ws();
  532. var id = consume(ID);
  533. if (id && id.value === "getter") {
  534. ret.names = ["getter"];
  535. }
  536. else if (id) {
  537. ret.names = [id.value];
  538. identifiers(ret.names);
  539. }
  540. else {
  541. ret.names = [];
  542. }
  543. all_ws();
  544. consume(OTHER, "]") || error("Unterminated serializer pattern list");
  545. }
  546. else {
  547. var name = consume(ID) || error("Invalid serializer");
  548. ret.name = name.value;
  549. }
  550. all_ws();
  551. consume(OTHER, ";") || error("Unterminated serializer");
  552. return ret;
  553. }
  554. else if (consume(OTHER, ";")) {
  555. // noop, just parsing
  556. }
  557. else {
  558. ret.idlType = return_type();
  559. all_ws();
  560. ret.operation = operation_rest();
  561. }
  562. return ret;
  563. };
  564. var interface_ = function (isPartial) {
  565. all_ws();
  566. if (!consume(ID, "interface")) return;
  567. all_ws();
  568. var name = consume(ID) || error("No name for interface");
  569. var ret = {
  570. type: "interface"
  571. , name: name.value
  572. , partial: false
  573. , members: []
  574. };
  575. if (!isPartial) ret.inheritance = inheritance() || null;
  576. all_ws();
  577. consume(OTHER, "{") || error("Bodyless interface");
  578. while (true) {
  579. all_ws();
  580. if (consume(OTHER, "}")) {
  581. all_ws();
  582. consume(OTHER, ";") || error("Missing semicolon after interface");
  583. return ret;
  584. }
  585. var ea = extended_attrs();
  586. all_ws();
  587. var cnt = const_();
  588. if (cnt) {
  589. cnt.extAttrs = ea;
  590. ret.members.push(cnt);
  591. continue;
  592. }
  593. var mem = serialiser() || attribute() || operation() || error("Unknown member");
  594. mem.extAttrs = ea;
  595. ret.members.push(mem);
  596. }
  597. };
  598. var partial = function () {
  599. all_ws();
  600. if (!consume(ID, "partial")) return;
  601. var thing = dictionary(true) || interface_(true) || error("Partial doesn't apply to anything");
  602. thing.partial = true;
  603. return thing;
  604. };
  605. var dictionary = function (isPartial) {
  606. all_ws();
  607. if (!consume(ID, "dictionary")) return;
  608. all_ws();
  609. var name = consume(ID) || error("No name for dictionary");
  610. var ret = {
  611. type: "dictionary"
  612. , name: name.value
  613. , partial: false
  614. , members: []
  615. };
  616. if (!isPartial) ret.inheritance = inheritance() || null;
  617. all_ws();
  618. consume(OTHER, "{") || error("Bodyless dictionary");
  619. while (true) {
  620. all_ws();
  621. if (consume(OTHER, "}")) {
  622. all_ws();
  623. consume(OTHER, ";") || error("Missing semicolon after dictionary");
  624. return ret;
  625. }
  626. var ea = extended_attrs();
  627. all_ws();
  628. var typ = type() || error("No type for dictionary member");
  629. all_ws();
  630. var name = consume(ID) || error("No name for dictionary member");
  631. ret.members.push({
  632. type: "field"
  633. , name: name.value
  634. , idlType: typ
  635. , extAttrs: ea
  636. , "default": default_()
  637. });
  638. all_ws();
  639. consume(OTHER, ";") || error("Unterminated dictionary member");
  640. }
  641. };
  642. var exception = function () {
  643. all_ws();
  644. if (!consume(ID, "exception")) return;
  645. all_ws();
  646. var name = consume(ID) || error("No name for exception");
  647. var ret = {
  648. type: "exception"
  649. , name: name.value
  650. , members: []
  651. };
  652. ret.inheritance = inheritance() || null;
  653. all_ws();
  654. consume(OTHER, "{") || error("Bodyless exception");
  655. while (true) {
  656. all_ws();
  657. if (consume(OTHER, "}")) {
  658. all_ws();
  659. consume(OTHER, ";") || error("Missing semicolon after exception");
  660. return ret;
  661. }
  662. var ea = extended_attrs();
  663. all_ws();
  664. var cnt = const_();
  665. if (cnt) {
  666. cnt.extAttrs = ea;
  667. ret.members.push(cnt);
  668. }
  669. else {
  670. var typ = type();
  671. all_ws();
  672. var name = consume(ID);
  673. all_ws();
  674. if (!typ || !name || !consume(OTHER, ";")) error("Unknown member in exception body");
  675. ret.members.push({
  676. type: "field"
  677. , name: name.value
  678. , idlType: typ
  679. , extAttrs: ea
  680. });
  681. }
  682. }
  683. };
  684. var enum_ = function () {
  685. all_ws();
  686. if (!consume(ID, "enum")) return;
  687. all_ws();
  688. var name = consume(ID) || error("No name for enum");
  689. var ret = {
  690. type: "enum"
  691. , name: name.value
  692. , values: []
  693. };
  694. all_ws();
  695. consume(OTHER, "{") || error("No curly for enum");
  696. var saw_comma = false;
  697. while (true) {
  698. all_ws();
  699. if (consume(OTHER, "}")) {
  700. all_ws();
  701. if (saw_comma) error("Trailing comma in enum");
  702. consume(OTHER, ";") || error("No semicolon after enum");
  703. return ret;
  704. }
  705. var val = consume(STR) || error("Unexpected value in enum");
  706. ret.values.push(val.value.replace(/"/g, ""));
  707. all_ws();
  708. if (consume(OTHER, ",")) {
  709. all_ws();
  710. saw_comma = true;
  711. }
  712. else {
  713. saw_comma = false;
  714. }
  715. }
  716. };
  717. var typedef = function () {
  718. all_ws();
  719. if (!consume(ID, "typedef")) return;
  720. var ret = {
  721. type: "typedef"
  722. };
  723. all_ws();
  724. ret.typeExtAttrs = extended_attrs();
  725. all_ws();
  726. ret.idlType = type() || error("No type in typedef");
  727. all_ws();
  728. var name = consume(ID) || error("No name in typedef");
  729. ret.name = name.value;
  730. all_ws();
  731. consume(OTHER, ";") || error("Unterminated typedef");
  732. return ret;
  733. };
  734. var implements_ = function () {
  735. all_ws();
  736. var target = consume(ID);
  737. if (!target) return;
  738. var w = all_ws();
  739. if (consume(ID, "implements")) {
  740. var ret = {
  741. type: "implements"
  742. , target: target.value
  743. };
  744. all_ws();
  745. var imp = consume(ID) || error("Incomplete implements statement");
  746. ret["implements"] = imp.value;
  747. all_ws();
  748. consume(OTHER, ";") || error("No terminating ; for implements statement");
  749. return ret;
  750. }
  751. else {
  752. // rollback
  753. tokens.unshift(w);
  754. tokens.unshift(target);
  755. }
  756. };
  757. var definition = function () {
  758. return callback() ||
  759. interface_() ||
  760. partial() ||
  761. dictionary() ||
  762. exception() ||
  763. enum_() ||
  764. typedef() ||
  765. implements_()
  766. ;
  767. };
  768. var definitions = function () {
  769. if (!tokens.length) return [];
  770. var defs = [];
  771. while (true) {
  772. var ea = extended_attrs()
  773. , def = definition();
  774. if (!def) {
  775. if (ea.length) error("Stray extended attributes");
  776. break;
  777. }
  778. def.extAttrs = ea;
  779. defs.push(def);
  780. }
  781. return defs;
  782. };
  783. var res = definitions();
  784. if (tokens.length) error("Unrecognised tokens");
  785. return res;
  786. };
  787. var obj = {
  788. parse: function (str) {
  789. var tokens = tokenise(str);
  790. return parse(tokens);
  791. }
  792. };
  793. if (typeof module !== "undefined" && module.exports) {
  794. module.exports = obj;
  795. }
  796. else {
  797. window.WebIDL2 = obj;
  798. }
  799. }());