1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/imptests/WebIDLParser.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,841 @@ 1.4 + 1.5 + 1.6 +(function () { 1.7 + var tokenise = function (str) { 1.8 + var tokens = [] 1.9 + , re = { 1.10 + "float": /^-?(([0-9]+\.[0-9]*|[0-9]*\.[0-9]+)([Ee][-+]?[0-9]+)?|[0-9]+[Ee][-+]?[0-9]+)/ 1.11 + , "integer": /^-?(0([Xx][0-9A-Fa-f]+|[0-7]*)|[1-9][0-9]*)/ 1.12 + , "identifier": /^[A-Z_a-z][0-9A-Z_a-z]*/ 1.13 + , "string": /^"[^"]*"/ 1.14 + , "whitespace": /^(?:[\t\n\r ]+|[\t\n\r ]*((\/\/.*|\/\*(.|\n|\r)*?\*\/)[\t\n\r ]*))+/ 1.15 + , "other": /^[^\t\n\r 0-9A-Z_a-z]/ 1.16 + } 1.17 + , types = [] 1.18 + ; 1.19 + for (var k in re) types.push(k); 1.20 + while (str.length > 0) { 1.21 + var matched = false; 1.22 + for (var i = 0, n = types.length; i < n; i++) { 1.23 + var type = types[i]; 1.24 + str = str.replace(re[type], function (tok) { 1.25 + tokens.push({ type: type, value: tok }); 1.26 + matched = true; 1.27 + return ""; 1.28 + }); 1.29 + if (matched) break; 1.30 + } 1.31 + if (matched) continue; 1.32 + throw new Error("Token stream not progressing"); 1.33 + } 1.34 + return tokens; 1.35 + }; 1.36 + 1.37 + var parse = function (tokens) { 1.38 + var line = 1; 1.39 + tokens = tokens.slice(); 1.40 + 1.41 + var FLOAT = "float" 1.42 + , INT = "integer" 1.43 + , ID = "identifier" 1.44 + , STR = "string" 1.45 + , OTHER = "other" 1.46 + ; 1.47 + 1.48 + var WebIDLParseError = function (str, line, input, tokens) { 1.49 + this.message = str; 1.50 + this.line = line; 1.51 + this.input = input; 1.52 + this.tokens = tokens; 1.53 + }; 1.54 + WebIDLParseError.prototype.toString = function () { 1.55 + return this.message + ", line " + this.line + " (tokens: '" + this.input + "')\n" + 1.56 + JSON.stringify(this.tokens, null, 4); 1.57 + }; 1.58 + 1.59 + var error = function (str) { 1.60 + var tok = "", numTokens = 0, maxTokens = 5; 1.61 + while (numTokens < maxTokens && tokens.length > numTokens) { 1.62 + tok += tokens[numTokens].value; 1.63 + numTokens++; 1.64 + } 1.65 + throw new WebIDLParseError(str, line, tok, tokens.slice(0, 5)); 1.66 + }; 1.67 + 1.68 + var last_token = null; 1.69 + 1.70 + var consume = function (type, value) { 1.71 + if (!tokens.length || tokens[0].type !== type) return; 1.72 + if (typeof value === "undefined" || tokens[0].value === value) { 1.73 + last_token = tokens.shift(); 1.74 + if (type === ID) last_token.value = last_token.value.replace(/^_/, ""); 1.75 + return last_token; 1.76 + } 1.77 + }; 1.78 + 1.79 + var ws = function () { 1.80 + if (!tokens.length) return; 1.81 + if (tokens[0].type === "whitespace") { 1.82 + var t = tokens.shift(); 1.83 + t.value.replace(/\n/g, function (m) { line++; return m; }); 1.84 + return t; 1.85 + } 1.86 + }; 1.87 + 1.88 + var all_ws = function () { 1.89 + var t = { type: "whitespace", value: "" }; 1.90 + while (true) { 1.91 + var w = ws(); 1.92 + if (!w) break; 1.93 + t.value += w.value; 1.94 + } 1.95 + if (t.value.length > 0) return t; 1.96 + }; 1.97 + 1.98 + var integer_type = function () { 1.99 + var ret = ""; 1.100 + all_ws(); 1.101 + if (consume(ID, "unsigned")) ret = "unsigned "; 1.102 + all_ws(); 1.103 + if (consume(ID, "short")) return ret + "short"; 1.104 + if (consume(ID, "long")) { 1.105 + ret += "long"; 1.106 + all_ws(); 1.107 + if (consume(ID, "long")) return ret + " long"; 1.108 + return ret; 1.109 + } 1.110 + if (ret) error("Failed to parse integer type"); 1.111 + }; 1.112 + 1.113 + var float_type = function () { 1.114 + var ret = ""; 1.115 + all_ws(); 1.116 + if (consume(ID, "unrestricted")) ret = "unrestricted "; 1.117 + all_ws(); 1.118 + if (consume(ID, "float")) return ret + "float"; 1.119 + if (consume(ID, "double")) return ret + "double"; 1.120 + if (ret) error("Failed to parse float type"); 1.121 + }; 1.122 + 1.123 + var primitive_type = function () { 1.124 + var num_type = integer_type() || float_type(); 1.125 + if (num_type) return num_type; 1.126 + all_ws(); 1.127 + if (consume(ID, "boolean")) return "boolean"; 1.128 + if (consume(ID, "byte")) return "byte"; 1.129 + if (consume(ID, "octet")) return "octet"; 1.130 + }; 1.131 + 1.132 + var const_value = function () { 1.133 + if (consume(ID, "true")) return { type: "boolean", value: true }; 1.134 + if (consume(ID, "false")) return { type: "boolean", value: false }; 1.135 + if (consume(ID, "null")) return { type: "null" }; 1.136 + if (consume(ID, "Infinity")) return { type: "Infinity", negative: false }; 1.137 + if (consume(ID, "NaN")) return { type: "NaN" }; 1.138 + var ret = consume(FLOAT) || consume(INT); 1.139 + if (ret) return { type: "number", value: 1 * ret.value }; 1.140 + var tok = consume(OTHER, "-"); 1.141 + if (tok) { 1.142 + if (consume(ID, "Infinity")) return { type: "Infinity", negative: true }; 1.143 + else tokens.unshift(tok); 1.144 + } 1.145 + }; 1.146 + 1.147 + var type_suffix = function (obj) { 1.148 + while (true) { 1.149 + all_ws(); 1.150 + if (consume(OTHER, "?")) { 1.151 + if (obj.nullable) error("Can't nullable more than once"); 1.152 + obj.nullable = true; 1.153 + } 1.154 + else if (consume(OTHER, "[")) { 1.155 + all_ws(); 1.156 + consume(OTHER, "]") || error("Unterminated array type"); 1.157 + if (!obj.array) obj.array = 1; 1.158 + else obj.array++; 1.159 + } 1.160 + else return; 1.161 + } 1.162 + }; 1.163 + 1.164 + var single_type = function () { 1.165 + var prim = primitive_type() 1.166 + , ret = { sequence: false, nullable: false, array: false, union: false } 1.167 + ; 1.168 + if (prim) { 1.169 + ret.idlType = prim; 1.170 + } 1.171 + else if (consume(ID, "sequence")) { 1.172 + all_ws(); 1.173 + if (!consume(OTHER, "<")) { 1.174 + ret.idlType = "sequence"; 1.175 + } 1.176 + else { 1.177 + ret.sequence = true; 1.178 + ret.idlType = type() || error("Error parsing sequence type"); 1.179 + all_ws(); 1.180 + if (!consume(OTHER, ">")) error("Unterminated sequence"); 1.181 + all_ws(); 1.182 + if (consume(OTHER, "?")) ret.nullable = true; 1.183 + return ret; 1.184 + } 1.185 + } 1.186 + else { 1.187 + var name = consume(ID); 1.188 + if (!name) return; 1.189 + ret.idlType = name.value; 1.190 + } 1.191 + type_suffix(ret); 1.192 + if (ret.nullable && ret.idlType === "any") error("Type any cannot be made nullable"); 1.193 + return ret; 1.194 + }; 1.195 + 1.196 + var union_type = function () { 1.197 + all_ws(); 1.198 + if (!consume(OTHER, "(")) return; 1.199 + var ret = { sequence: false, nullable: false, array: false, union: true, idlType: [] }; 1.200 + var fst = type() || error("Union type with no content"); 1.201 + ret.idlType.push(fst); 1.202 + while (true) { 1.203 + all_ws(); 1.204 + if (!consume(ID, "or")) break; 1.205 + var typ = type() || error("No type after 'or' in union type"); 1.206 + ret.idlType.push(typ); 1.207 + } 1.208 + if (!consume(OTHER, ")")) error("Unterminated union type"); 1.209 + type_suffix(ret); 1.210 + return ret; 1.211 + }; 1.212 + 1.213 + var type = function () { 1.214 + return single_type() || union_type(); 1.215 + }; 1.216 + 1.217 + var argument = function () { 1.218 + var ret = { optional: false, variadic: false }; 1.219 + ret.extAttrs = extended_attrs(); 1.220 + all_ws(); 1.221 + if (consume(ID, "optional")) { 1.222 + ret.optional = true; 1.223 + all_ws(); 1.224 + } 1.225 + ret.idlType = type(); 1.226 + if (!ret.idlType) return; 1.227 + if (!ret.optional) { 1.228 + all_ws(); 1.229 + if (tokens.length >= 3 && 1.230 + tokens[0].type === "other" && tokens[0].value === "." && 1.231 + tokens[1].type === "other" && tokens[1].value === "." && 1.232 + tokens[2].type === "other" && tokens[2].value === "." 1.233 + ) { 1.234 + tokens.shift(); 1.235 + tokens.shift(); 1.236 + tokens.shift(); 1.237 + ret.variadic = true; 1.238 + } 1.239 + } 1.240 + all_ws(); 1.241 + var name = consume(ID) || error("No name in argument"); 1.242 + ret.name = name.value; 1.243 + if (ret.optional) { 1.244 + all_ws(); 1.245 + ret["default"] = default_(); 1.246 + } 1.247 + return ret; 1.248 + }; 1.249 + 1.250 + var argument_list = function () { 1.251 + var arg = argument(), ret = []; 1.252 + if (!arg) return ret; 1.253 + ret.push(arg); 1.254 + while (true) { 1.255 + all_ws(); 1.256 + if (!consume(OTHER, ",")) return ret; 1.257 + all_ws(); 1.258 + var nxt = argument() || error("Trailing comma in arguments list"); 1.259 + ret.push(nxt); 1.260 + } 1.261 + }; 1.262 + 1.263 + var simple_extended_attr = function () { 1.264 + all_ws(); 1.265 + var name = consume(ID); 1.266 + if (!name) return; 1.267 + var ret = { 1.268 + name: name.value 1.269 + , "arguments": null 1.270 + }; 1.271 + all_ws(); 1.272 + var eq = consume(OTHER, "="); 1.273 + if (eq) { 1.274 + all_ws(); 1.275 + ret.rhs = consume(ID); 1.276 + if (!ret.rhs) return error("No right hand side to extended attribute assignment"); 1.277 + } 1.278 + all_ws(); 1.279 + if (consume(OTHER, "(")) { 1.280 + ret["arguments"] = argument_list(); 1.281 + all_ws(); 1.282 + consume(OTHER, ")") || error("Unclosed argument in extended attribute"); 1.283 + } 1.284 + return ret; 1.285 + }; 1.286 + 1.287 + // Note: we parse something simpler than the official syntax. It's all that ever 1.288 + // seems to be used 1.289 + var extended_attrs = function () { 1.290 + var eas = []; 1.291 + all_ws(); 1.292 + if (!consume(OTHER, "[")) return eas; 1.293 + eas[0] = simple_extended_attr() || error("Extended attribute with not content"); 1.294 + all_ws(); 1.295 + while (consume(OTHER, ",")) { 1.296 + all_ws(); 1.297 + eas.push(simple_extended_attr() || error("Trailing comma in extended attribute")); 1.298 + all_ws(); 1.299 + } 1.300 + consume(OTHER, "]") || error("No end of extended attribute"); 1.301 + return eas; 1.302 + }; 1.303 + 1.304 + var default_ = function () { 1.305 + all_ws(); 1.306 + if (consume(OTHER, "=")) { 1.307 + all_ws(); 1.308 + var def = const_value(); 1.309 + if (def) { 1.310 + return def; 1.311 + } 1.312 + else { 1.313 + var str = consume(STR) || error("No value for default"); 1.314 + str.value = str.value.replace(/^"/, "").replace(/"$/, ""); 1.315 + return str; 1.316 + } 1.317 + } 1.318 + }; 1.319 + 1.320 + var const_ = function () { 1.321 + all_ws(); 1.322 + if (!consume(ID, "const")) return; 1.323 + var ret = { type: "const", nullable: false }; 1.324 + all_ws(); 1.325 + var typ = primitive_type(); 1.326 + if (!typ) { 1.327 + typ = consume(ID) || error("No type for const"); 1.328 + typ = typ.value; 1.329 + } 1.330 + ret.idlType = typ; 1.331 + all_ws(); 1.332 + if (consume(OTHER, "?")) { 1.333 + ret.nullable = true; 1.334 + all_ws(); 1.335 + } 1.336 + var name = consume(ID) || error("No name for const"); 1.337 + ret.name = name.value; 1.338 + all_ws(); 1.339 + consume(OTHER, "=") || error("No value assignment for const"); 1.340 + all_ws(); 1.341 + var cnt = const_value(); 1.342 + if (cnt) ret.value = cnt; 1.343 + else error("No value for const"); 1.344 + all_ws(); 1.345 + consume(OTHER, ";") || error("Unterminated const"); 1.346 + return ret; 1.347 + }; 1.348 + 1.349 + var inheritance = function () { 1.350 + all_ws(); 1.351 + if (consume(OTHER, ":")) { 1.352 + all_ws(); 1.353 + var inh = consume(ID) || error ("No type in inheritance"); 1.354 + return inh.value; 1.355 + } 1.356 + }; 1.357 + 1.358 + var operation_rest = function (ret) { 1.359 + all_ws(); 1.360 + if (!ret) ret = {}; 1.361 + var name = consume(ID); 1.362 + ret.name = name ? name.value : null; 1.363 + all_ws(); 1.364 + consume(OTHER, "(") || error("Invalid operation"); 1.365 + ret["arguments"] = argument_list(); 1.366 + all_ws(); 1.367 + consume(OTHER, ")") || error("Unterminated operation"); 1.368 + all_ws(); 1.369 + consume(OTHER, ";") || error("Unterminated operation"); 1.370 + return ret; 1.371 + }; 1.372 + 1.373 + var callback = function () { 1.374 + all_ws(); 1.375 + var ret; 1.376 + if (!consume(ID, "callback")) return; 1.377 + all_ws(); 1.378 + var tok = consume(ID, "interface"); 1.379 + if (tok) { 1.380 + tokens.unshift(tok); 1.381 + ret = interface_(); 1.382 + ret.type = "callback interface"; 1.383 + return ret; 1.384 + } 1.385 + var name = consume(ID) || error("No name for callback"); 1.386 + ret = { type: "callback", name: name.value }; 1.387 + all_ws(); 1.388 + consume(OTHER, "=") || error("No assignment in callback"); 1.389 + all_ws(); 1.390 + ret.idlType = return_type(); 1.391 + all_ws(); 1.392 + consume(OTHER, "(") || error("No arguments in callback"); 1.393 + ret["arguments"] = argument_list(); 1.394 + all_ws(); 1.395 + consume(OTHER, ")") || error("Unterminated callback"); 1.396 + all_ws(); 1.397 + consume(OTHER, ";") || error("Unterminated callback"); 1.398 + return ret; 1.399 + }; 1.400 + 1.401 + var attribute = function () { 1.402 + all_ws(); 1.403 + var grabbed = [] 1.404 + , ret = { 1.405 + type: "attribute" 1.406 + , "static": false 1.407 + , stringifier: false 1.408 + , inherit: false 1.409 + , readonly: false 1.410 + }; 1.411 + if (consume(ID, "static")) { 1.412 + ret["static"] = true; 1.413 + grabbed.push(last_token); 1.414 + } 1.415 + else if (consume(ID, "stringifier")) { 1.416 + ret.stringifier = true; 1.417 + grabbed.push(last_token); 1.418 + } 1.419 + var w = all_ws(); 1.420 + if (w) grabbed.push(w); 1.421 + if (consume(ID, "inherit")) { 1.422 + if (ret["static"] || ret.stringifier) error("Cannot have a static or stringifier inherit"); 1.423 + ret.inherit = true; 1.424 + grabbed.push(last_token); 1.425 + var w = all_ws(); 1.426 + if (w) grabbed.push(w); 1.427 + } 1.428 + if (consume(ID, "readonly")) { 1.429 + ret.readonly = true; 1.430 + grabbed.push(last_token); 1.431 + var w = all_ws(); 1.432 + if (w) grabbed.push(w); 1.433 + } 1.434 + if (!consume(ID, "attribute")) { 1.435 + tokens = grabbed.concat(tokens); 1.436 + return; 1.437 + } 1.438 + all_ws(); 1.439 + ret.idlType = type() || error("No type in attribute"); 1.440 + if (ret.idlType.sequence) error("Attributes cannot accept sequence types"); 1.441 + all_ws(); 1.442 + var name = consume(ID) || error("No name in attribute"); 1.443 + ret.name = name.value; 1.444 + all_ws(); 1.445 + consume(OTHER, ";") || error("Unterminated attribute"); 1.446 + return ret; 1.447 + }; 1.448 + 1.449 + var return_type = function () { 1.450 + var typ = type(); 1.451 + if (!typ) { 1.452 + if (consume(ID, "void")) { 1.453 + return "void"; 1.454 + } 1.455 + else error("No return type"); 1.456 + } 1.457 + return typ; 1.458 + }; 1.459 + 1.460 + var operation = function () { 1.461 + all_ws(); 1.462 + var ret = { 1.463 + type: "operation" 1.464 + , getter: false 1.465 + , setter: false 1.466 + , creator: false 1.467 + , deleter: false 1.468 + , legacycaller: false 1.469 + , "static": false 1.470 + , stringifier: false 1.471 + }; 1.472 + while (true) { 1.473 + all_ws(); 1.474 + if (consume(ID, "getter")) ret.getter = true; 1.475 + else if (consume(ID, "setter")) ret.setter = true; 1.476 + else if (consume(ID, "creator")) ret.creator = true; 1.477 + else if (consume(ID, "deleter")) ret.deleter = true; 1.478 + else if (consume(ID, "legacycaller")) ret.legacycaller = true; 1.479 + else break; 1.480 + } 1.481 + if (ret.getter || ret.setter || ret.creator || ret.deleter || ret.legacycaller) { 1.482 + all_ws(); 1.483 + ret.idlType = return_type(); 1.484 + operation_rest(ret); 1.485 + return ret; 1.486 + } 1.487 + if (consume(ID, "static")) { 1.488 + ret["static"] = true; 1.489 + ret.idlType = return_type(); 1.490 + operation_rest(ret); 1.491 + return ret; 1.492 + } 1.493 + else if (consume(ID, "stringifier")) { 1.494 + ret.stringifier = true; 1.495 + all_ws(); 1.496 + if (consume(OTHER, ";")) return ret; 1.497 + ret.idlType = return_type(); 1.498 + operation_rest(ret); 1.499 + return ret; 1.500 + } 1.501 + ret.idlType = return_type(); 1.502 + all_ws(); 1.503 + if (consume(ID, "iterator")) { 1.504 + all_ws(); 1.505 + ret.type = "iterator"; 1.506 + if (consume(ID, "object")) { 1.507 + ret.iteratorObject = "object"; 1.508 + } 1.509 + else if (consume(OTHER, "=")) { 1.510 + all_ws(); 1.511 + var name = consume(ID) || error("No right hand side in iterator"); 1.512 + ret.iteratorObject = name.value; 1.513 + } 1.514 + all_ws(); 1.515 + consume(OTHER, ";") || error("Unterminated iterator"); 1.516 + return ret; 1.517 + } 1.518 + else { 1.519 + operation_rest(ret); 1.520 + return ret; 1.521 + } 1.522 + }; 1.523 + 1.524 + var identifiers = function (arr) { 1.525 + while (true) { 1.526 + all_ws(); 1.527 + if (consume(OTHER, ",")) { 1.528 + all_ws(); 1.529 + var name = consume(ID) || error("Trailing comma in identifiers list"); 1.530 + arr.push(name.value); 1.531 + } 1.532 + else break; 1.533 + } 1.534 + }; 1.535 + 1.536 + var serialiser = function () { 1.537 + all_ws(); 1.538 + if (!consume(ID, "serializer")) return; 1.539 + var ret = { type: "serializer" }; 1.540 + all_ws(); 1.541 + if (consume(OTHER, "=")) { 1.542 + all_ws(); 1.543 + if (consume(OTHER, "{")) { 1.544 + ret.patternMap = true; 1.545 + all_ws(); 1.546 + var id = consume(ID); 1.547 + if (id && id.value === "getter") { 1.548 + ret.names = ["getter"]; 1.549 + } 1.550 + else if (id && id.value === "inherit") { 1.551 + ret.names = ["inherit"]; 1.552 + identifiers(ret.names); 1.553 + } 1.554 + else if (id) { 1.555 + ret.names = [id.value]; 1.556 + identifiers(ret.names); 1.557 + } 1.558 + else { 1.559 + ret.names = []; 1.560 + } 1.561 + all_ws(); 1.562 + consume(OTHER, "}") || error("Unterminated serializer pattern map"); 1.563 + } 1.564 + else if (consume(OTHER, "[")) { 1.565 + ret.patternList = true; 1.566 + all_ws(); 1.567 + var id = consume(ID); 1.568 + if (id && id.value === "getter") { 1.569 + ret.names = ["getter"]; 1.570 + } 1.571 + else if (id) { 1.572 + ret.names = [id.value]; 1.573 + identifiers(ret.names); 1.574 + } 1.575 + else { 1.576 + ret.names = []; 1.577 + } 1.578 + all_ws(); 1.579 + consume(OTHER, "]") || error("Unterminated serializer pattern list"); 1.580 + } 1.581 + else { 1.582 + var name = consume(ID) || error("Invalid serializer"); 1.583 + ret.name = name.value; 1.584 + } 1.585 + all_ws(); 1.586 + consume(OTHER, ";") || error("Unterminated serializer"); 1.587 + return ret; 1.588 + } 1.589 + else if (consume(OTHER, ";")) { 1.590 + // noop, just parsing 1.591 + } 1.592 + else { 1.593 + ret.idlType = return_type(); 1.594 + all_ws(); 1.595 + ret.operation = operation_rest(); 1.596 + } 1.597 + return ret; 1.598 + }; 1.599 + 1.600 + var interface_ = function (isPartial) { 1.601 + all_ws(); 1.602 + if (!consume(ID, "interface")) return; 1.603 + all_ws(); 1.604 + var name = consume(ID) || error("No name for interface"); 1.605 + var ret = { 1.606 + type: "interface" 1.607 + , name: name.value 1.608 + , partial: false 1.609 + , members: [] 1.610 + }; 1.611 + if (!isPartial) ret.inheritance = inheritance() || null; 1.612 + all_ws(); 1.613 + consume(OTHER, "{") || error("Bodyless interface"); 1.614 + while (true) { 1.615 + all_ws(); 1.616 + if (consume(OTHER, "}")) { 1.617 + all_ws(); 1.618 + consume(OTHER, ";") || error("Missing semicolon after interface"); 1.619 + return ret; 1.620 + } 1.621 + var ea = extended_attrs(); 1.622 + all_ws(); 1.623 + var cnt = const_(); 1.624 + if (cnt) { 1.625 + cnt.extAttrs = ea; 1.626 + ret.members.push(cnt); 1.627 + continue; 1.628 + } 1.629 + var mem = serialiser() || attribute() || operation() || error("Unknown member"); 1.630 + mem.extAttrs = ea; 1.631 + ret.members.push(mem); 1.632 + } 1.633 + }; 1.634 + 1.635 + var partial = function () { 1.636 + all_ws(); 1.637 + if (!consume(ID, "partial")) return; 1.638 + var thing = dictionary(true) || interface_(true) || error("Partial doesn't apply to anything"); 1.639 + thing.partial = true; 1.640 + return thing; 1.641 + }; 1.642 + 1.643 + var dictionary = function (isPartial) { 1.644 + all_ws(); 1.645 + if (!consume(ID, "dictionary")) return; 1.646 + all_ws(); 1.647 + var name = consume(ID) || error("No name for dictionary"); 1.648 + var ret = { 1.649 + type: "dictionary" 1.650 + , name: name.value 1.651 + , partial: false 1.652 + , members: [] 1.653 + }; 1.654 + if (!isPartial) ret.inheritance = inheritance() || null; 1.655 + all_ws(); 1.656 + consume(OTHER, "{") || error("Bodyless dictionary"); 1.657 + while (true) { 1.658 + all_ws(); 1.659 + if (consume(OTHER, "}")) { 1.660 + all_ws(); 1.661 + consume(OTHER, ";") || error("Missing semicolon after dictionary"); 1.662 + return ret; 1.663 + } 1.664 + var ea = extended_attrs(); 1.665 + all_ws(); 1.666 + var typ = type() || error("No type for dictionary member"); 1.667 + all_ws(); 1.668 + var name = consume(ID) || error("No name for dictionary member"); 1.669 + ret.members.push({ 1.670 + type: "field" 1.671 + , name: name.value 1.672 + , idlType: typ 1.673 + , extAttrs: ea 1.674 + , "default": default_() 1.675 + }); 1.676 + all_ws(); 1.677 + consume(OTHER, ";") || error("Unterminated dictionary member"); 1.678 + } 1.679 + }; 1.680 + 1.681 + var exception = function () { 1.682 + all_ws(); 1.683 + if (!consume(ID, "exception")) return; 1.684 + all_ws(); 1.685 + var name = consume(ID) || error("No name for exception"); 1.686 + var ret = { 1.687 + type: "exception" 1.688 + , name: name.value 1.689 + , members: [] 1.690 + }; 1.691 + ret.inheritance = inheritance() || null; 1.692 + all_ws(); 1.693 + consume(OTHER, "{") || error("Bodyless exception"); 1.694 + while (true) { 1.695 + all_ws(); 1.696 + if (consume(OTHER, "}")) { 1.697 + all_ws(); 1.698 + consume(OTHER, ";") || error("Missing semicolon after exception"); 1.699 + return ret; 1.700 + } 1.701 + var ea = extended_attrs(); 1.702 + all_ws(); 1.703 + var cnt = const_(); 1.704 + if (cnt) { 1.705 + cnt.extAttrs = ea; 1.706 + ret.members.push(cnt); 1.707 + } 1.708 + else { 1.709 + var typ = type(); 1.710 + all_ws(); 1.711 + var name = consume(ID); 1.712 + all_ws(); 1.713 + if (!typ || !name || !consume(OTHER, ";")) error("Unknown member in exception body"); 1.714 + ret.members.push({ 1.715 + type: "field" 1.716 + , name: name.value 1.717 + , idlType: typ 1.718 + , extAttrs: ea 1.719 + }); 1.720 + } 1.721 + } 1.722 + }; 1.723 + 1.724 + var enum_ = function () { 1.725 + all_ws(); 1.726 + if (!consume(ID, "enum")) return; 1.727 + all_ws(); 1.728 + var name = consume(ID) || error("No name for enum"); 1.729 + var ret = { 1.730 + type: "enum" 1.731 + , name: name.value 1.732 + , values: [] 1.733 + }; 1.734 + all_ws(); 1.735 + consume(OTHER, "{") || error("No curly for enum"); 1.736 + var saw_comma = false; 1.737 + while (true) { 1.738 + all_ws(); 1.739 + if (consume(OTHER, "}")) { 1.740 + all_ws(); 1.741 + if (saw_comma) error("Trailing comma in enum"); 1.742 + consume(OTHER, ";") || error("No semicolon after enum"); 1.743 + return ret; 1.744 + } 1.745 + var val = consume(STR) || error("Unexpected value in enum"); 1.746 + ret.values.push(val.value.replace(/"/g, "")); 1.747 + all_ws(); 1.748 + if (consume(OTHER, ",")) { 1.749 + all_ws(); 1.750 + saw_comma = true; 1.751 + } 1.752 + else { 1.753 + saw_comma = false; 1.754 + } 1.755 + } 1.756 + }; 1.757 + 1.758 + var typedef = function () { 1.759 + all_ws(); 1.760 + if (!consume(ID, "typedef")) return; 1.761 + var ret = { 1.762 + type: "typedef" 1.763 + }; 1.764 + all_ws(); 1.765 + ret.typeExtAttrs = extended_attrs(); 1.766 + all_ws(); 1.767 + ret.idlType = type() || error("No type in typedef"); 1.768 + all_ws(); 1.769 + var name = consume(ID) || error("No name in typedef"); 1.770 + ret.name = name.value; 1.771 + all_ws(); 1.772 + consume(OTHER, ";") || error("Unterminated typedef"); 1.773 + return ret; 1.774 + }; 1.775 + 1.776 + var implements_ = function () { 1.777 + all_ws(); 1.778 + var target = consume(ID); 1.779 + if (!target) return; 1.780 + var w = all_ws(); 1.781 + if (consume(ID, "implements")) { 1.782 + var ret = { 1.783 + type: "implements" 1.784 + , target: target.value 1.785 + }; 1.786 + all_ws(); 1.787 + var imp = consume(ID) || error("Incomplete implements statement"); 1.788 + ret["implements"] = imp.value; 1.789 + all_ws(); 1.790 + consume(OTHER, ";") || error("No terminating ; for implements statement"); 1.791 + return ret; 1.792 + } 1.793 + else { 1.794 + // rollback 1.795 + tokens.unshift(w); 1.796 + tokens.unshift(target); 1.797 + } 1.798 + }; 1.799 + 1.800 + var definition = function () { 1.801 + return callback() || 1.802 + interface_() || 1.803 + partial() || 1.804 + dictionary() || 1.805 + exception() || 1.806 + enum_() || 1.807 + typedef() || 1.808 + implements_() 1.809 + ; 1.810 + }; 1.811 + 1.812 + var definitions = function () { 1.813 + if (!tokens.length) return []; 1.814 + var defs = []; 1.815 + while (true) { 1.816 + var ea = extended_attrs() 1.817 + , def = definition(); 1.818 + if (!def) { 1.819 + if (ea.length) error("Stray extended attributes"); 1.820 + break; 1.821 + } 1.822 + def.extAttrs = ea; 1.823 + defs.push(def); 1.824 + } 1.825 + return defs; 1.826 + }; 1.827 + var res = definitions(); 1.828 + if (tokens.length) error("Unrecognised tokens"); 1.829 + return res; 1.830 + }; 1.831 + 1.832 + var obj = { 1.833 + parse: function (str) { 1.834 + var tokens = tokenise(str); 1.835 + return parse(tokens); 1.836 + } 1.837 + }; 1.838 + if (typeof module !== "undefined" && module.exports) { 1.839 + module.exports = obj; 1.840 + } 1.841 + else { 1.842 + window.WebIDL2 = obj; 1.843 + } 1.844 +}());