| OLD | NEW |
| (Empty) |
| 1 | |
| 2 | |
| 3 (function () { | |
| 4 var tokenise = function (str) { | |
| 5 var tokens = [] | |
| 6 , re = { | |
| 7 "float": /^-?(([0-9]+\.[0-9]*|[0-9]*\.[0-9]+)([Ee][-+]?[0
-9]+)?|[0-9]+[Ee][-+]?[0-9]+)/ | |
| 8 , "integer": /^-?(0([Xx][0-9A-Fa-f]+|[0-7]*)|[1-9][0-9]*)/ | |
| 9 , "identifier": /^[A-Z_a-z][0-9A-Z_a-z]*/ | |
| 10 , "string": /^"[^"]*"/ | |
| 11 , "whitespace": /^(?:[\t\n\r ]+|[\t\n\r ]*((\/\/.*|\/\*(.|\n|\r)
*?\*\/)[\t\n\r ]*))+/ | |
| 12 , "other": /^[^\t\n\r 0-9A-Z_a-z]/ | |
| 13 } | |
| 14 , types = [] | |
| 15 ; | |
| 16 for (var k in re) types.push(k); | |
| 17 while (str.length > 0) { | |
| 18 var matched = false; | |
| 19 for (var i = 0, n = types.length; i < n; i++) { | |
| 20 var type = types[i]; | |
| 21 str = str.replace(re[type], function (tok) { | |
| 22 tokens.push({ type: type, value: tok }); | |
| 23 matched = true; | |
| 24 return ""; | |
| 25 }); | |
| 26 if (matched) break; | |
| 27 } | |
| 28 if (matched) continue; | |
| 29 throw new Error("Token stream not progressing"); | |
| 30 } | |
| 31 return tokens; | |
| 32 }; | |
| 33 | |
| 34 var parse = function (tokens, opt) { | |
| 35 var line = 1; | |
| 36 tokens = tokens.slice(); | |
| 37 | |
| 38 var FLOAT = "float" | |
| 39 , INT = "integer" | |
| 40 , ID = "identifier" | |
| 41 , STR = "string" | |
| 42 , OTHER = "other" | |
| 43 ; | |
| 44 | |
| 45 var WebIDLParseError = function (str, line, input, tokens) { | |
| 46 this.message = str; | |
| 47 this.line = line; | |
| 48 this.input = input; | |
| 49 this.tokens = tokens; | |
| 50 }; | |
| 51 WebIDLParseError.prototype.toString = function () { | |
| 52 return this.message + ", line " + this.line + " (tokens: '" + this.i
nput + "')\n" + | |
| 53 JSON.stringify(this.tokens, null, 4); | |
| 54 }; | |
| 55 | |
| 56 var error = function (str) { | |
| 57 var tok = "", numTokens = 0, maxTokens = 5; | |
| 58 while (numTokens < maxTokens && tokens.length > numTokens) { | |
| 59 tok += tokens[numTokens].value; | |
| 60 numTokens++; | |
| 61 } | |
| 62 throw new WebIDLParseError(str, line, tok, tokens.slice(0, 5)); | |
| 63 }; | |
| 64 | |
| 65 var last_token = null; | |
| 66 | |
| 67 var consume = function (type, value) { | |
| 68 if (!tokens.length || tokens[0].type !== type) return; | |
| 69 if (typeof value === "undefined" || tokens[0].value === value) { | |
| 70 last_token = tokens.shift(); | |
| 71 if (type === ID) last_token.value = last_token.value.replace(/^
_/, ""); | |
| 72 return last_token; | |
| 73 } | |
| 74 }; | |
| 75 | |
| 76 var ws = function () { | |
| 77 if (!tokens.length) return; | |
| 78 if (tokens[0].type === "whitespace") { | |
| 79 var t = tokens.shift(); | |
| 80 t.value.replace(/\n/g, function (m) { line++; return m; }); | |
| 81 return t; | |
| 82 } | |
| 83 }; | |
| 84 | |
| 85 var all_ws = function (store, pea) { // pea == post extended attribute,
tpea = same for types | |
| 86 var t = { type: "whitespace", value: "" }; | |
| 87 while (true) { | |
| 88 var w = ws(); | |
| 89 if (!w) break; | |
| 90 t.value += w.value; | |
| 91 } | |
| 92 if (t.value.length > 0) { | |
| 93 if (store) { | |
| 94 var w = t.value | |
| 95 , re = { | |
| 96 "ws": /^([\t\n\r ]+)/ | |
| 97 , "line-comment": /^\/\/(.*)\n?/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 + (pea ? ("-" + pea) : "
"), 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 } | |
| 120 }; | |
| 121 | |
| 122 var integer_type = function () { | |
| 123 var ret = ""; | |
| 124 all_ws(); | |
| 125 if (consume(ID, "unsigned")) ret = "unsigned "; | |
| 126 all_ws(); | |
| 127 if (consume(ID, "short")) return ret + "short"; | |
| 128 if (consume(ID, "long")) { | |
| 129 ret += "long"; | |
| 130 all_ws(); | |
| 131 if (consume(ID, "long")) return ret + " long"; | |
| 132 return ret; | |
| 133 } | |
| 134 if (ret) error("Failed to parse integer type"); | |
| 135 }; | |
| 136 | |
| 137 var float_type = function () { | |
| 138 var ret = ""; | |
| 139 all_ws(); | |
| 140 if (consume(ID, "unrestricted")) ret = "unrestricted "; | |
| 141 all_ws(); | |
| 142 if (consume(ID, "float")) return ret + "float"; | |
| 143 if (consume(ID, "double")) return ret + "double"; | |
| 144 if (ret) error("Failed to parse float type"); | |
| 145 }; | |
| 146 | |
| 147 var primitive_type = function () { | |
| 148 var num_type = integer_type() || float_type(); | |
| 149 if (num_type) return num_type; | |
| 150 all_ws(); | |
| 151 if (consume(ID, "boolean")) return "boolean"; | |
| 152 if (consume(ID, "byte")) return "byte"; | |
| 153 if (consume(ID, "octet")) return "octet"; | |
| 154 }; | |
| 155 | |
| 156 var const_value = function () { | |
| 157 if (consume(ID, "true")) return { type: "boolean", value: true }; | |
| 158 if (consume(ID, "false")) return { type: "boolean", value: false }; | |
| 159 if (consume(ID, "null")) return { type: "null" }; | |
| 160 if (consume(ID, "Infinity")) return { type: "Infinity", negative: fa
lse }; | |
| 161 if (consume(ID, "NaN")) return { type: "NaN" }; | |
| 162 var ret = consume(FLOAT) || consume(INT); | |
| 163 if (ret) return { type: "number", value: 1 * ret.value }; | |
| 164 var tok = consume(OTHER, "-"); | |
| 165 if (tok) { | |
| 166 if (consume(ID, "Infinity")) return { type: "Infinity", negative
: true }; | |
| 167 else tokens.unshift(tok); | |
| 168 } | |
| 169 }; | |
| 170 | |
| 171 var type_suffix = function (obj) { | |
| 172 while (true) { | |
| 173 all_ws(); | |
| 174 if (consume(OTHER, "?")) { | |
| 175 if (obj.nullable) error("Can't nullable more than once"); | |
| 176 obj.nullable = true; | |
| 177 } | |
| 178 else if (consume(OTHER, "[")) { | |
| 179 all_ws(); | |
| 180 consume(OTHER, "]") || error("Unterminated array type"); | |
| 181 if (!obj.array) { | |
| 182 obj.array = 1; | |
| 183 obj.nullableArray = [obj.nullable]; | |
| 184 } | |
| 185 else { | |
| 186 obj.array++; | |
| 187 obj.nullableArray.push(obj.nullable); | |
| 188 } | |
| 189 obj.nullable = false; | |
| 190 } | |
| 191 else return; | |
| 192 } | |
| 193 }; | |
| 194 | |
| 195 var single_type = function () { | |
| 196 var prim = primitive_type() | |
| 197 , ret = { sequence: false, generic: null, nullable: false, array:
false, union: false } | |
| 198 , name | |
| 199 , value | |
| 200 ; | |
| 201 if (prim) { | |
| 202 ret.idlType = prim; | |
| 203 } | |
| 204 else if (name = consume(ID)) { | |
| 205 value = name.value; | |
| 206 all_ws(); | |
| 207 // Generic types | |
| 208 if (consume(OTHER, "<")) { | |
| 209 // backwards compat | |
| 210 if (value === "sequence") { | |
| 211 ret.sequence = true; | |
| 212 } | |
| 213 ret.generic = value; | |
| 214 ret.idlType = type() || error("Error parsing generic type "
+ value); | |
| 215 all_ws(); | |
| 216 if (!consume(OTHER, ">")) error("Unterminated generic type "
+ value); | |
| 217 type_suffix(ret); | |
| 218 return ret; | |
| 219 } | |
| 220 else { | |
| 221 ret.idlType = value; | |
| 222 } | |
| 223 } | |
| 224 else { | |
| 225 return; | |
| 226 } | |
| 227 type_suffix(ret); | |
| 228 if (ret.nullable && !ret.array && ret.idlType === "any") error("Type
any cannot be made nullable"); | |
| 229 return ret; | |
| 230 }; | |
| 231 | |
| 232 var union_type = function () { | |
| 233 all_ws(); | |
| 234 if (!consume(OTHER, "(")) return; | |
| 235 var ret = { sequence: false, generic: null, nullable: false, array:
false, union: true, idlType: [] }; | |
| 236 var fst = type() || error("Union type with no content"); | |
| 237 ret.idlType.push(fst); | |
| 238 while (true) { | |
| 239 all_ws(); | |
| 240 if (!consume(ID, "or")) break; | |
| 241 var typ = type() || error("No type after 'or' in union type"); | |
| 242 ret.idlType.push(typ); | |
| 243 } | |
| 244 if (!consume(OTHER, ")")) error("Unterminated union type"); | |
| 245 type_suffix(ret); | |
| 246 return ret; | |
| 247 }; | |
| 248 | |
| 249 var type = function () { | |
| 250 return single_type() || union_type(); | |
| 251 }; | |
| 252 | |
| 253 var argument = function (store) { | |
| 254 var ret = { optional: false, variadic: false }; | |
| 255 ret.extAttrs = extended_attrs(store); | |
| 256 all_ws(store, "pea"); | |
| 257 var opt_token = consume(ID, "optional"); | |
| 258 if (opt_token) { | |
| 259 ret.optional = true; | |
| 260 all_ws(); | |
| 261 } | |
| 262 ret.idlType = type(); | |
| 263 if (!ret.idlType) { | |
| 264 if (opt_token) tokens.unshift(opt_token); | |
| 265 return; | |
| 266 } | |
| 267 var type_token = last_token; | |
| 268 if (!ret.optional) { | |
| 269 all_ws(); | |
| 270 if (tokens.length >= 3 && | |
| 271 tokens[0].type === "other" && tokens[0].value === "." && | |
| 272 tokens[1].type === "other" && tokens[1].value === "." && | |
| 273 tokens[2].type === "other" && tokens[2].value === "." | |
| 274 ) { | |
| 275 tokens.shift(); | |
| 276 tokens.shift(); | |
| 277 tokens.shift(); | |
| 278 ret.variadic = true; | |
| 279 } | |
| 280 } | |
| 281 all_ws(); | |
| 282 var name = consume(ID); | |
| 283 if (!name) { | |
| 284 if (opt_token) tokens.unshift(opt_token); | |
| 285 tokens.unshift(type_token); | |
| 286 return; | |
| 287 } | |
| 288 ret.name = name.value; | |
| 289 if (ret.optional) { | |
| 290 all_ws(); | |
| 291 ret["default"] = default_(); | |
| 292 } | |
| 293 return ret; | |
| 294 }; | |
| 295 | |
| 296 var argument_list = function (store) { | |
| 297 var ret = [] | |
| 298 , arg = argument(store ? ret : null) | |
| 299 ; | |
| 300 if (!arg) return; | |
| 301 ret.push(arg); | |
| 302 while (true) { | |
| 303 all_ws(store ? ret : null); | |
| 304 if (!consume(OTHER, ",")) return ret; | |
| 305 var nxt = argument(store ? ret : null) || error("Trailing comma
in arguments list"); | |
| 306 ret.push(nxt); | |
| 307 } | |
| 308 }; | |
| 309 | |
| 310 var type_pair = function () { | |
| 311 all_ws(); | |
| 312 var k = type(); | |
| 313 if (!k) return; | |
| 314 all_ws() | |
| 315 if (!consume(OTHER, ",")) return; | |
| 316 all_ws(); | |
| 317 var v = type(); | |
| 318 if (!v) return; | |
| 319 return [k, v]; | |
| 320 }; | |
| 321 | |
| 322 var simple_extended_attr = function (store) { | |
| 323 all_ws(); | |
| 324 var name = consume(ID); | |
| 325 if (!name) return; | |
| 326 var ret = { | |
| 327 name: name.value | |
| 328 , "arguments": null | |
| 329 }; | |
| 330 all_ws(); | |
| 331 var eq = consume(OTHER, "="); | |
| 332 if (eq) { | |
| 333 var rhs; | |
| 334 all_ws(); | |
| 335 if (rhs = consume(ID)) { | |
| 336 ret.rhs = rhs | |
| 337 } | |
| 338 else if (consume(OTHER, "(")) { | |
| 339 // [Exposed=(Window,Worker)] | |
| 340 rhs = []; | |
| 341 var id = consume(ID); | |
| 342 if (id) { | |
| 343 rhs = [id.value]; | |
| 344 } | |
| 345 identifiers(rhs); | |
| 346 consume(OTHER, ")") || error("Unexpected token in extended a
ttribute argument list or type pair"); | |
| 347 ret.rhs = { | |
| 348 type: "identifier-list", | |
| 349 value: rhs | |
| 350 }; | |
| 351 } | |
| 352 if (!ret.rhs) return error("No right hand side to extended attri
bute assignment"); | |
| 353 } | |
| 354 all_ws(); | |
| 355 if (consume(OTHER, "(")) { | |
| 356 var args, pair; | |
| 357 // [Constructor(DOMString str)] | |
| 358 if (args = argument_list(store)) { | |
| 359 ret["arguments"] = args; | |
| 360 } | |
| 361 // [MapClass(DOMString, DOMString)] | |
| 362 else if (pair = type_pair()) { | |
| 363 ret.typePair = pair; | |
| 364 } | |
| 365 // [Constructor()] | |
| 366 else { | |
| 367 ret["arguments"] = []; | |
| 368 } | |
| 369 all_ws(); | |
| 370 consume(OTHER, ")") || error("Unexpected token in extended attri
bute argument list or type pair"); | |
| 371 } | |
| 372 return ret; | |
| 373 }; | |
| 374 | |
| 375 // Note: we parse something simpler than the official syntax. It's all t
hat ever | |
| 376 // seems to be used | |
| 377 var extended_attrs = function (store) { | |
| 378 var eas = []; | |
| 379 all_ws(store); | |
| 380 if (!consume(OTHER, "[")) return eas; | |
| 381 eas[0] = simple_extended_attr(store) || error("Extended attribute wi
th not content"); | |
| 382 all_ws(); | |
| 383 while (consume(OTHER, ",")) { | |
| 384 eas.push(simple_extended_attr(store) || error("Trailing comma in
extended attribute")); | |
| 385 all_ws(); | |
| 386 } | |
| 387 consume(OTHER, "]") || error("No end of extended attribute"); | |
| 388 return eas; | |
| 389 }; | |
| 390 | |
| 391 var default_ = function () { | |
| 392 all_ws(); | |
| 393 if (consume(OTHER, "=")) { | |
| 394 all_ws(); | |
| 395 var def = const_value(); | |
| 396 if (def) { | |
| 397 return def; | |
| 398 } | |
| 399 else if (consume(OTHER, "[")) { | |
| 400 if (!consume(OTHER, "]")) error("Default sequence value must
be empty"); | |
| 401 return { type: "sequence", value: [] }; | |
| 402 } | |
| 403 else { | |
| 404 var str = consume(STR) || error("No value for default"); | |
| 405 str.value = str.value.replace(/^"/, "").replace(/"$/, ""); | |
| 406 return str; | |
| 407 } | |
| 408 } | |
| 409 }; | |
| 410 | |
| 411 var const_ = function (store) { | |
| 412 all_ws(store, "pea"); | |
| 413 if (!consume(ID, "const")) return; | |
| 414 var ret = { type: "const", nullable: false }; | |
| 415 all_ws(); | |
| 416 var typ = primitive_type(); | |
| 417 if (!typ) { | |
| 418 typ = consume(ID) || error("No type for const"); | |
| 419 typ = typ.value; | |
| 420 } | |
| 421 ret.idlType = typ; | |
| 422 all_ws(); | |
| 423 if (consume(OTHER, "?")) { | |
| 424 ret.nullable = true; | |
| 425 all_ws(); | |
| 426 } | |
| 427 var name = consume(ID) || error("No name for const"); | |
| 428 ret.name = name.value; | |
| 429 all_ws(); | |
| 430 consume(OTHER, "=") || error("No value assignment for const"); | |
| 431 all_ws(); | |
| 432 var cnt = const_value(); | |
| 433 if (cnt) ret.value = cnt; | |
| 434 else error("No value for const"); | |
| 435 all_ws(); | |
| 436 consume(OTHER, ";") || error("Unterminated const"); | |
| 437 return ret; | |
| 438 }; | |
| 439 | |
| 440 var inheritance = function () { | |
| 441 all_ws(); | |
| 442 if (consume(OTHER, ":")) { | |
| 443 all_ws(); | |
| 444 var inh = consume(ID) || error ("No type in inheritance"); | |
| 445 return inh.value; | |
| 446 } | |
| 447 }; | |
| 448 | |
| 449 var operation_rest = function (ret, store) { | |
| 450 all_ws(); | |
| 451 if (!ret) ret = {}; | |
| 452 var name = consume(ID); | |
| 453 ret.name = name ? name.value : null; | |
| 454 all_ws(); | |
| 455 consume(OTHER, "(") || error("Invalid operation"); | |
| 456 ret["arguments"] = argument_list(store) || []; | |
| 457 all_ws(); | |
| 458 consume(OTHER, ")") || error("Unterminated operation"); | |
| 459 all_ws(); | |
| 460 consume(OTHER, ";") || error("Unterminated operation"); | |
| 461 return ret; | |
| 462 }; | |
| 463 | |
| 464 var callback = function (store) { | |
| 465 all_ws(store, "pea"); | |
| 466 var ret; | |
| 467 if (!consume(ID, "callback")) return; | |
| 468 all_ws(); | |
| 469 var tok = consume(ID, "interface"); | |
| 470 if (tok) { | |
| 471 tokens.unshift(tok); | |
| 472 ret = interface_(); | |
| 473 ret.type = "callback interface"; | |
| 474 return ret; | |
| 475 } | |
| 476 var name = consume(ID) || error("No name for callback"); | |
| 477 ret = { type: "callback", name: name.value }; | |
| 478 all_ws(); | |
| 479 consume(OTHER, "=") || error("No assignment in callback"); | |
| 480 all_ws(); | |
| 481 ret.idlType = return_type(); | |
| 482 all_ws(); | |
| 483 consume(OTHER, "(") || error("No arguments in callback"); | |
| 484 ret["arguments"] = argument_list(store) || []; | |
| 485 all_ws(); | |
| 486 consume(OTHER, ")") || error("Unterminated callback"); | |
| 487 all_ws(); | |
| 488 consume(OTHER, ";") || error("Unterminated callback"); | |
| 489 return ret; | |
| 490 }; | |
| 491 | |
| 492 var attribute = function (store) { | |
| 493 all_ws(store, "pea"); | |
| 494 var grabbed = [] | |
| 495 , ret = { | |
| 496 type: "attribute" | |
| 497 , "static": false | |
| 498 , stringifier: false | |
| 499 , inherit: false | |
| 500 , readonly: false | |
| 501 }; | |
| 502 if (consume(ID, "static")) { | |
| 503 ret["static"] = true; | |
| 504 grabbed.push(last_token); | |
| 505 } | |
| 506 else if (consume(ID, "stringifier")) { | |
| 507 ret.stringifier = true; | |
| 508 grabbed.push(last_token); | |
| 509 } | |
| 510 var w = all_ws(); | |
| 511 if (w) grabbed.push(w); | |
| 512 if (consume(ID, "inherit")) { | |
| 513 if (ret["static"] || ret.stringifier) error("Cannot have a stati
c or stringifier inherit"); | |
| 514 ret.inherit = true; | |
| 515 grabbed.push(last_token); | |
| 516 var w = all_ws(); | |
| 517 if (w) grabbed.push(w); | |
| 518 } | |
| 519 if (consume(ID, "readonly")) { | |
| 520 ret.readonly = true; | |
| 521 grabbed.push(last_token); | |
| 522 var w = all_ws(); | |
| 523 if (w) grabbed.push(w); | |
| 524 } | |
| 525 if (!consume(ID, "attribute")) { | |
| 526 tokens = grabbed.concat(tokens); | |
| 527 return; | |
| 528 } | |
| 529 all_ws(); | |
| 530 ret.idlType = type() || error("No type in attribute"); | |
| 531 if (ret.idlType.sequence) error("Attributes cannot accept sequence t
ypes"); | |
| 532 all_ws(); | |
| 533 var name = consume(ID) || error("No name in attribute"); | |
| 534 ret.name = name.value; | |
| 535 all_ws(); | |
| 536 consume(OTHER, ";") || error("Unterminated attribute"); | |
| 537 return ret; | |
| 538 }; | |
| 539 | |
| 540 var return_type = function () { | |
| 541 var typ = type(); | |
| 542 if (!typ) { | |
| 543 if (consume(ID, "void")) { | |
| 544 return "void"; | |
| 545 } | |
| 546 else error("No return type"); | |
| 547 } | |
| 548 return typ; | |
| 549 }; | |
| 550 | |
| 551 var operation = function (store) { | |
| 552 all_ws(store, "pea"); | |
| 553 var ret = { | |
| 554 type: "operation" | |
| 555 , getter: false | |
| 556 , setter: false | |
| 557 , creator: false | |
| 558 , deleter: false | |
| 559 , legacycaller: false | |
| 560 , "static": false | |
| 561 , stringifier: false | |
| 562 }; | |
| 563 while (true) { | |
| 564 all_ws(); | |
| 565 if (consume(ID, "getter")) ret.getter = true; | |
| 566 else if (consume(ID, "setter")) ret.setter = true; | |
| 567 else if (consume(ID, "creator")) ret.creator = true; | |
| 568 else if (consume(ID, "deleter")) ret.deleter = true; | |
| 569 else if (consume(ID, "legacycaller")) ret.legacycaller = true; | |
| 570 else break; | |
| 571 } | |
| 572 if (ret.getter || ret.setter || ret.creator || ret.deleter || ret.le
gacycaller) { | |
| 573 all_ws(); | |
| 574 ret.idlType = return_type(); | |
| 575 operation_rest(ret, store); | |
| 576 return ret; | |
| 577 } | |
| 578 if (consume(ID, "static")) { | |
| 579 ret["static"] = true; | |
| 580 ret.idlType = return_type(); | |
| 581 operation_rest(ret, store); | |
| 582 return ret; | |
| 583 } | |
| 584 else if (consume(ID, "stringifier")) { | |
| 585 ret.stringifier = true;- | |
| 586 all_ws(); | |
| 587 if (consume(OTHER, ";")) return ret; | |
| 588 ret.idlType = return_type(); | |
| 589 operation_rest(ret, store); | |
| 590 return ret; | |
| 591 } | |
| 592 ret.idlType = return_type(); | |
| 593 all_ws(); | |
| 594 if (consume(ID, "iterator")) { | |
| 595 all_ws(); | |
| 596 ret.type = "iterator"; | |
| 597 if (consume(ID, "object")) { | |
| 598 ret.iteratorObject = "object"; | |
| 599 } | |
| 600 else if (consume(OTHER, "=")) { | |
| 601 all_ws(); | |
| 602 var name = consume(ID) || error("No right hand side in itera
tor"); | |
| 603 ret.iteratorObject = name.value; | |
| 604 } | |
| 605 all_ws(); | |
| 606 consume(OTHER, ";") || error("Unterminated iterator"); | |
| 607 return ret; | |
| 608 } | |
| 609 else { | |
| 610 operation_rest(ret, store); | |
| 611 return ret; | |
| 612 } | |
| 613 }; | |
| 614 | |
| 615 var identifiers = function (arr) { | |
| 616 while (true) { | |
| 617 all_ws(); | |
| 618 if (consume(OTHER, ",")) { | |
| 619 all_ws(); | |
| 620 var name = consume(ID) || error("Trailing comma in identifie
rs list"); | |
| 621 arr.push(name.value); | |
| 622 } | |
| 623 else break; | |
| 624 } | |
| 625 }; | |
| 626 | |
| 627 var serialiser = function (store) { | |
| 628 all_ws(store, "pea"); | |
| 629 if (!consume(ID, "serializer")) return; | |
| 630 var ret = { type: "serializer" }; | |
| 631 all_ws(); | |
| 632 if (consume(OTHER, "=")) { | |
| 633 all_ws(); | |
| 634 if (consume(OTHER, "{")) { | |
| 635 ret.patternMap = true; | |
| 636 all_ws(); | |
| 637 var id = consume(ID); | |
| 638 if (id && id.value === "getter") { | |
| 639 ret.names = ["getter"]; | |
| 640 } | |
| 641 else if (id && id.value === "inherit") { | |
| 642 ret.names = ["inherit"]; | |
| 643 identifiers(ret.names); | |
| 644 } | |
| 645 else if (id) { | |
| 646 ret.names = [id.value]; | |
| 647 identifiers(ret.names); | |
| 648 } | |
| 649 else { | |
| 650 ret.names = []; | |
| 651 } | |
| 652 all_ws(); | |
| 653 consume(OTHER, "}") || error("Unterminated serializer patter
n map"); | |
| 654 } | |
| 655 else if (consume(OTHER, "[")) { | |
| 656 ret.patternList = true; | |
| 657 all_ws(); | |
| 658 var id = consume(ID); | |
| 659 if (id && id.value === "getter") { | |
| 660 ret.names = ["getter"]; | |
| 661 } | |
| 662 else if (id) { | |
| 663 ret.names = [id.value]; | |
| 664 identifiers(ret.names); | |
| 665 } | |
| 666 else { | |
| 667 ret.names = []; | |
| 668 } | |
| 669 all_ws(); | |
| 670 consume(OTHER, "]") || error("Unterminated serializer patter
n list"); | |
| 671 } | |
| 672 else { | |
| 673 var name = consume(ID) || error("Invalid serializer"); | |
| 674 ret.name = name.value; | |
| 675 } | |
| 676 all_ws(); | |
| 677 consume(OTHER, ";") || error("Unterminated serializer"); | |
| 678 return ret; | |
| 679 } | |
| 680 else if (consume(OTHER, ";")) { | |
| 681 // noop, just parsing | |
| 682 } | |
| 683 else { | |
| 684 ret.idlType = return_type(); | |
| 685 all_ws(); | |
| 686 ret.operation = operation_rest(null, store); | |
| 687 } | |
| 688 return ret; | |
| 689 }; | |
| 690 | |
| 691 var iterable_type = function() { | |
| 692 if (consume(ID, "iterable")) return "iterable"; | |
| 693 else if (consume(ID, "legacyiterable")) return "legacyiterable"; | |
| 694 else if (consume(ID, "maplike")) return "maplike"; | |
| 695 else if (consume(ID, "setlike")) return "setlike"; | |
| 696 else return; | |
| 697 } | |
| 698 | |
| 699 var readonly_iterable_type = function() { | |
| 700 if (consume(ID, "maplike")) return "maplike"; | |
| 701 else if (consume(ID, "setlike")) return "setlike"; | |
| 702 else return; | |
| 703 } | |
| 704 | |
| 705 var iterable = function (store) { | |
| 706 all_ws(store, "pea"); | |
| 707 var grabbed = [], | |
| 708 ret = {type: null, idlType: null, readonly: false}; | |
| 709 if (consume(ID, "readonly")) { | |
| 710 ret.readonly = true; | |
| 711 grabbed.push(last_token); | |
| 712 var w = all_ws(); | |
| 713 if (w) grabbed.push(w); | |
| 714 } | |
| 715 var consumeItType = ret.readonly ? readonly_iterable_type : iterable
_type; | |
| 716 | |
| 717 var ittype = consumeItType(); | |
| 718 if (!ittype) { | |
| 719 tokens = grabbed.concat(tokens); | |
| 720 return; | |
| 721 } | |
| 722 | |
| 723 var secondTypeRequired = ittype === "maplike"; | |
| 724 var secondTypeAllowed = secondTypeRequired || ittype === "iterable"; | |
| 725 ret.type = ittype; | |
| 726 if (ret.type !== 'maplike' && ret.type !== 'setlike') | |
| 727 delete ret.readonly; | |
| 728 all_ws(); | |
| 729 if (consume(OTHER, "<")) { | |
| 730 ret.idlType = type() || error("Error parsing " + ittype + " decl
aration"); | |
| 731 all_ws(); | |
| 732 if (secondTypeAllowed) { | |
| 733 var type2 = null; | |
| 734 if (consume(OTHER, ",")) { | |
| 735 all_ws(); | |
| 736 type2 = type(); | |
| 737 all_ws(); | |
| 738 } | |
| 739 if (type2) | |
| 740 ret.idlType = [ret.idlType, type2]; | |
| 741 else if (secondTypeRequired) | |
| 742 error("Missing second type argument in " + ittype + " de
claration"); | |
| 743 } | |
| 744 if (!consume(OTHER, ">")) error("Unterminated " + ittype + " dec
laration"); | |
| 745 all_ws(); | |
| 746 if (!consume(OTHER, ";")) error("Missing semicolon after " + itt
ype + " declaration"); | |
| 747 } | |
| 748 else | |
| 749 error("Error parsing " + ittype + " declaration"); | |
| 750 | |
| 751 return ret; | |
| 752 } | |
| 753 | |
| 754 var interface_ = function (isPartial, store) { | |
| 755 all_ws(isPartial ? null : store, "pea"); | |
| 756 if (!consume(ID, "interface")) return; | |
| 757 all_ws(); | |
| 758 var name = consume(ID) || error("No name for interface"); | |
| 759 var mems = [] | |
| 760 , ret = { | |
| 761 type: "interface" | |
| 762 , name: name.value | |
| 763 , partial: false | |
| 764 , members: mems | |
| 765 }; | |
| 766 if (!isPartial) ret.inheritance = inheritance() || null; | |
| 767 all_ws(); | |
| 768 consume(OTHER, "{") || error("Bodyless interface"); | |
| 769 while (true) { | |
| 770 all_ws(store ? mems : null); | |
| 771 if (consume(OTHER, "}")) { | |
| 772 all_ws(); | |
| 773 consume(OTHER, ";") || error("Missing semicolon after interf
ace"); | |
| 774 return ret; | |
| 775 } | |
| 776 var ea = extended_attrs(store ? mems : null); | |
| 777 all_ws(); | |
| 778 var cnt = const_(store ? mems : null); | |
| 779 if (cnt) { | |
| 780 cnt.extAttrs = ea; | |
| 781 ret.members.push(cnt); | |
| 782 continue; | |
| 783 } | |
| 784 var mem = (opt.allowNestedTypedefs && typedef(store ? mems : nul
l)) || | |
| 785 iterable(store ? mems : null) || | |
| 786 serialiser(store ? mems : null) || | |
| 787 attribute(store ? mems : null) || | |
| 788 operation(store ? mems : null) || | |
| 789 error("Unknown member"); | |
| 790 mem.extAttrs = ea; | |
| 791 ret.members.push(mem); | |
| 792 } | |
| 793 }; | |
| 794 | |
| 795 var partial = function (store) { | |
| 796 all_ws(store, "pea"); | |
| 797 if (!consume(ID, "partial")) return; | |
| 798 var thing = dictionary(true, store) || | |
| 799 interface_(true, store) || | |
| 800 error("Partial doesn't apply to anything"); | |
| 801 thing.partial = true; | |
| 802 return thing; | |
| 803 }; | |
| 804 | |
| 805 var dictionary = function (isPartial, store) { | |
| 806 all_ws(isPartial ? null : store, "pea"); | |
| 807 if (!consume(ID, "dictionary")) return; | |
| 808 all_ws(); | |
| 809 var name = consume(ID) || error("No name for dictionary"); | |
| 810 var mems = [] | |
| 811 , ret = { | |
| 812 type: "dictionary" | |
| 813 , name: name.value | |
| 814 , partial: false | |
| 815 , members: mems | |
| 816 }; | |
| 817 if (!isPartial) ret.inheritance = inheritance() || null; | |
| 818 all_ws(); | |
| 819 consume(OTHER, "{") || error("Bodyless dictionary"); | |
| 820 while (true) { | |
| 821 all_ws(store ? mems : null); | |
| 822 if (consume(OTHER, "}")) { | |
| 823 all_ws(); | |
| 824 consume(OTHER, ";") || error("Missing semicolon after dictio
nary"); | |
| 825 return ret; | |
| 826 } | |
| 827 var ea = extended_attrs(store ? mems : null); | |
| 828 all_ws(store ? mems : null, "pea"); | |
| 829 var required = consume(ID, "required"); | |
| 830 var typ = type() || error("No type for dictionary member"); | |
| 831 all_ws(); | |
| 832 var name = consume(ID) || error("No name for dictionary member")
; | |
| 833 var dflt = default_(); | |
| 834 if (required && dflt) error("Required member must not have a def
ault"); | |
| 835 ret.members.push({ | |
| 836 type: "field" | |
| 837 , name: name.value | |
| 838 , required: !!required | |
| 839 , idlType: typ | |
| 840 , extAttrs: ea | |
| 841 , "default": dflt | |
| 842 }); | |
| 843 all_ws(); | |
| 844 consume(OTHER, ";") || error("Unterminated dictionary member"); | |
| 845 } | |
| 846 }; | |
| 847 | |
| 848 var exception = function (store) { | |
| 849 all_ws(store, "pea"); | |
| 850 if (!consume(ID, "exception")) return; | |
| 851 all_ws(); | |
| 852 var name = consume(ID) || error("No name for exception"); | |
| 853 var mems = [] | |
| 854 , ret = { | |
| 855 type: "exception" | |
| 856 , name: name.value | |
| 857 , members: mems | |
| 858 }; | |
| 859 ret.inheritance = inheritance() || null; | |
| 860 all_ws(); | |
| 861 consume(OTHER, "{") || error("Bodyless exception"); | |
| 862 while (true) { | |
| 863 all_ws(store ? mems : null); | |
| 864 if (consume(OTHER, "}")) { | |
| 865 all_ws(); | |
| 866 consume(OTHER, ";") || error("Missing semicolon after except
ion"); | |
| 867 return ret; | |
| 868 } | |
| 869 var ea = extended_attrs(store ? mems : null); | |
| 870 all_ws(store ? mems : null, "pea"); | |
| 871 var cnt = const_(); | |
| 872 if (cnt) { | |
| 873 cnt.extAttrs = ea; | |
| 874 ret.members.push(cnt); | |
| 875 } | |
| 876 else { | |
| 877 var typ = type(); | |
| 878 all_ws(); | |
| 879 var name = consume(ID); | |
| 880 all_ws(); | |
| 881 if (!typ || !name || !consume(OTHER, ";")) error("Unknown me
mber in exception body"); | |
| 882 ret.members.push({ | |
| 883 type: "field" | |
| 884 , name: name.value | |
| 885 , idlType: typ | |
| 886 , extAttrs: ea | |
| 887 }); | |
| 888 } | |
| 889 } | |
| 890 }; | |
| 891 | |
| 892 var enum_ = function (store) { | |
| 893 all_ws(store, "pea"); | |
| 894 if (!consume(ID, "enum")) return; | |
| 895 all_ws(); | |
| 896 var name = consume(ID) || error("No name for enum"); | |
| 897 var vals = [] | |
| 898 , ret = { | |
| 899 type: "enum" | |
| 900 , name: name.value | |
| 901 , values: vals | |
| 902 }; | |
| 903 all_ws(); | |
| 904 consume(OTHER, "{") || error("No curly for enum"); | |
| 905 var saw_comma = false; | |
| 906 while (true) { | |
| 907 all_ws(store ? vals : null); | |
| 908 if (consume(OTHER, "}")) { | |
| 909 all_ws(); | |
| 910 consume(OTHER, ";") || error("No semicolon after enum"); | |
| 911 return ret; | |
| 912 } | |
| 913 var val = consume(STR) || error("Unexpected value in enum"); | |
| 914 ret.values.push(val.value.replace(/"/g, "")); | |
| 915 all_ws(store ? vals : null); | |
| 916 if (consume(OTHER, ",")) { | |
| 917 if (store) vals.push({ type: "," }); | |
| 918 all_ws(store ? vals : null); | |
| 919 saw_comma = true; | |
| 920 } | |
| 921 else { | |
| 922 saw_comma = false; | |
| 923 } | |
| 924 } | |
| 925 }; | |
| 926 | |
| 927 var typedef = function (store) { | |
| 928 all_ws(store, "pea"); | |
| 929 if (!consume(ID, "typedef")) return; | |
| 930 var ret = { | |
| 931 type: "typedef" | |
| 932 }; | |
| 933 all_ws(); | |
| 934 ret.typeExtAttrs = extended_attrs(); | |
| 935 all_ws(store, "tpea"); | |
| 936 ret.idlType = type() || error("No type in typedef"); | |
| 937 all_ws(); | |
| 938 var name = consume(ID) || error("No name in typedef"); | |
| 939 ret.name = name.value; | |
| 940 all_ws(); | |
| 941 consume(OTHER, ";") || error("Unterminated typedef"); | |
| 942 return ret; | |
| 943 }; | |
| 944 | |
| 945 var implements_ = function (store) { | |
| 946 all_ws(store, "pea"); | |
| 947 var target = consume(ID); | |
| 948 if (!target) return; | |
| 949 var w = all_ws(); | |
| 950 if (consume(ID, "implements")) { | |
| 951 var ret = { | |
| 952 type: "implements" | |
| 953 , target: target.value | |
| 954 }; | |
| 955 all_ws(); | |
| 956 var imp = consume(ID) || error("Incomplete implements statement"
); | |
| 957 ret["implements"] = imp.value; | |
| 958 all_ws(); | |
| 959 consume(OTHER, ";") || error("No terminating ; for implements st
atement"); | |
| 960 return ret; | |
| 961 } | |
| 962 else { | |
| 963 // rollback | |
| 964 tokens.unshift(w); | |
| 965 tokens.unshift(target); | |
| 966 } | |
| 967 }; | |
| 968 | |
| 969 var definition = function (store) { | |
| 970 return callback(store) || | |
| 971 interface_(false, store) || | |
| 972 partial(store) || | |
| 973 dictionary(false, store) || | |
| 974 exception(store) || | |
| 975 enum_(store) || | |
| 976 typedef(store) || | |
| 977 implements_(store) | |
| 978 ; | |
| 979 }; | |
| 980 | |
| 981 var definitions = function (store) { | |
| 982 if (!tokens.length) return []; | |
| 983 var defs = []; | |
| 984 while (true) { | |
| 985 var ea = extended_attrs(store ? defs : null) | |
| 986 , def = definition(store ? defs : null); | |
| 987 if (!def) { | |
| 988 if (ea.length) error("Stray extended attributes"); | |
| 989 break; | |
| 990 } | |
| 991 def.extAttrs = ea; | |
| 992 defs.push(def); | |
| 993 } | |
| 994 return defs; | |
| 995 }; | |
| 996 var res = definitions(opt.ws); | |
| 997 if (tokens.length) error("Unrecognised tokens"); | |
| 998 return res; | |
| 999 }; | |
| 1000 | |
| 1001 var inNode = typeof module !== "undefined" && module.exports | |
| 1002 , obj = { | |
| 1003 parse: function (str, opt) { | |
| 1004 if (!opt) opt = {}; | |
| 1005 var tokens = tokenise(str); | |
| 1006 return parse(tokens, opt); | |
| 1007 } | |
| 1008 }; | |
| 1009 | |
| 1010 if (inNode) module.exports = obj; | |
| 1011 else self.WebIDL2 = obj; | |
| 1012 }()); | |
| OLD | NEW |