���� JFIF �� � ( %"1"%)+...383,7(-.-
![]() Server : Apache/2.4.6 (CentOS) OpenSSL/1.0.2k-fips PHP/7.4.20 System : Linux st2.domain.com 3.10.0-1127.10.1.el7.x86_64 #1 SMP Wed Jun 3 14:28:03 UTC 2020 x86_64 User : apache ( 48) PHP Version : 7.4.20 Disable Function : NONE Directory : /home/real/node-v13.0.1/test/fixtures/wpt/resources/webidl2/lib/ |
"use strict"; (() => { // These regular expressions use the sticky flag so they will only match at // the current location (ie. the offset of lastIndex). const tokenRe = { // This expression uses a lookahead assertion to catch false matches // against integers early. "float": /-?(?=[0-9]*\.|[0-9]+[eE])(([0-9]+\.[0-9]*|[0-9]*\.[0-9]+)([Ee][-+]?[0-9]+)?|[0-9]+[Ee][-+]?[0-9]+)/y, "integer": /-?(0([Xx][0-9A-Fa-f]+|[0-7]*)|[1-9][0-9]*)/y, "identifier": /_?[A-Za-z][0-9A-Z_a-z-]*/y, "string": /"[^"]*"/y, "whitespace": /[\t\n\r ]+/y, "comment": /((\/(\/.*|\*([^*]|\*[^\/])*\*\/)[\t\n\r ]*)+)/y, "other": /[^\t\n\r 0-9A-Za-z]/y }; const stringTypes = [ "ByteString", "DOMString", "USVString" ]; const argumentNameKeywords = [ "attribute", "callback", "const", "deleter", "dictionary", "enum", "getter", "includes", "inherit", "interface", "iterable", "maplike", "namespace", "partial", "required", "setlike", "setter", "static", "stringifier", "typedef", "unrestricted" ]; const nonRegexTerminals = [ "FrozenArray", "Infinity", "NaN", "Promise", "boolean", "byte", "double", "false", "float", "implements", "legacyiterable", "long", "mixin", "null", "octet", "optional", "or", "readonly", "record", "sequence", "short", "true", "unsigned", "void" ].concat(argumentNameKeywords, stringTypes); const punctuations = [ "(", ")", ",", "-Infinity", "...", ":", ";", "<", "=", ">", "?", "[", "]", "{", "}" ]; function tokenise(str) { const tokens = []; let lastIndex = 0; let trivia = ""; while (lastIndex < str.length) { const nextChar = str.charAt(lastIndex); let result = -1; if (/[\t\n\r ]/.test(nextChar)) { result = attemptTokenMatch("whitespace", { noFlushTrivia: true }); } else if (nextChar === '/') { result = attemptTokenMatch("comment", { noFlushTrivia: true }); } if (result !== -1) { trivia += tokens.pop().value; } else if (/[-0-9.]/.test(nextChar)) { result = attemptTokenMatch("float"); if (result === -1) { result = attemptTokenMatch("integer"); } } else if (/[A-Z_a-z]/.test(nextChar)) { result = attemptTokenMatch("identifier"); const token = tokens[tokens.length - 1]; if (result !== -1 && nonRegexTerminals.includes(token.value)) { token.type = token.value; } } else if (nextChar === '"') { result = attemptTokenMatch("string"); } for (const punctuation of punctuations) { if (str.startsWith(punctuation, lastIndex)) { tokens.push({ type: punctuation, value: punctuation, trivia }); trivia = ""; lastIndex += punctuation.length; result = lastIndex; break; } } // other as the last try if (result === -1) { result = attemptTokenMatch("other"); } if (result === -1) { throw new Error("Token stream not progressing"); } lastIndex = result; } return tokens; function attemptTokenMatch(type, { noFlushTrivia } = {}) { const re = tokenRe[type]; re.lastIndex = lastIndex; const result = re.exec(str); if (result) { tokens.push({ type, value: result[0], trivia }); if (!noFlushTrivia) { trivia = ""; } return re.lastIndex; } return -1; } } class WebIDLParseError { constructor(str, line, input, tokens) { this.message = str; this.line = line; this.input = input; this.tokens = tokens; } toString() { const escapedInput = JSON.stringify(this.input); const tokens = JSON.stringify(this.tokens, null, 4); return `${this.message}, line ${this.line} (tokens: ${escapedInput})\n${tokens}`; } } function parse(tokens) { let line = 1; tokens = tokens.slice(); const names = new Map(); let current = null; const FLOAT = "float"; const INT = "integer"; const ID = "identifier"; const STR = "string"; const OTHER = "other"; const EMPTY_OPERATION = Object.freeze({ type: "operation", getter: false, setter: false, deleter: false, static: false, stringifier: false }); const EMPTY_IDLTYPE = Object.freeze({ generic: null, nullable: false, union: false, idlType: null, extAttrs: [] }); function error(str) { const maxTokens = 5; const tok = tokens .slice(consume_position, consume_position + maxTokens) .map(t => t.trivia + t.value).join(""); // Count newlines preceding the actual erroneous token if (tokens.length) { line += count(tokens[consume_position].trivia, "\n"); } let message; if (current) { message = `Got an error during or right after parsing \`${current.partial ? "partial " : ""}${current.type} ${current.name}\`: ${str}` } else { // throwing before any valid definition message = `Got an error before parsing any named definition: ${str}`; } throw new WebIDLParseError(message, line, tok, tokens.slice(0, maxTokens)); } function sanitize_name(name, type) { if (names.has(name)) { error(`The name "${name}" of type "${names.get(name)}" is already seen`); } names.set(name, type); return name; } let consume_position = 0; function probe(type) { return tokens.length > consume_position && tokens[consume_position].type === type; } function consume(...candidates) { // TODO: use const when Servo updates its JS engine for (let type of candidates) { if (!probe(type)) continue; const token = tokens[consume_position]; consume_position++; line += count(token.trivia, "\n"); return token; } } function unescape(identifier) { return identifier.startsWith('_') ? identifier.slice(1) : identifier; } function unconsume(position) { while (consume_position > position) { consume_position--; line -= count(tokens[consume_position].trivia, "\n"); } } function count(str, char) { let total = 0; for (let i = str.indexOf(char); i !== -1; i = str.indexOf(char, i + 1)) { ++total; } return total; } function integer_type() { let ret = ""; if (consume("unsigned")) ret = "unsigned "; if (consume("short")) return ret + "short"; if (consume("long")) { ret += "long"; if (consume("long")) return ret + " long"; return ret; } if (ret) error("Failed to parse integer type"); } function float_type() { let ret = ""; if (consume("unrestricted")) ret = "unrestricted "; if (consume("float")) return ret + "float"; if (consume("double")) return ret + "double"; if (ret) error("Failed to parse float type"); } function primitive_type() { const num_type = integer_type() || float_type(); if (num_type) return num_type; if (consume("boolean")) return "boolean"; if (consume("byte")) return "byte"; if (consume("octet")) return "octet"; } function const_value() { if (consume("true")) return { type: "boolean", value: true }; if (consume("false")) return { type: "boolean", value: false }; if (consume("null")) return { type: "null" }; if (consume("Infinity")) return { type: "Infinity", negative: false }; if (consume("-Infinity")) return { type: "Infinity", negative: true }; if (consume("NaN")) return { type: "NaN" }; const ret = consume(FLOAT, INT); if (ret) return { type: "number", value: ret.value }; } function type_suffix(obj) { obj.nullable = !!consume("?"); if (probe("?")) error("Can't nullable more than once"); } function generic_type(typeName) { const name = consume("FrozenArray", "Promise", "sequence", "record"); if (!name) { return; } const ret = { generic: name.type }; consume("<") || error(`No opening bracket after ${name.type}`); switch (name.type) { case "Promise": if (probe("[")) error("Promise type cannot have extended attribute"); ret.idlType = return_type(typeName); break; case "sequence": case "FrozenArray": ret.idlType = type_with_extended_attributes(typeName); break; case "record": if (probe("[")) error("Record key cannot have extended attribute"); ret.idlType = []; const keyType = consume(...stringTypes); if (!keyType) error(`Record key must be a string type`); ret.idlType.push(Object.assign({ type: typeName }, EMPTY_IDLTYPE, { idlType: keyType.value })); consume(",") || error("Missing comma after record key type"); const valueType = type_with_extended_attributes(typeName) || error("Error parsing generic type record"); ret.idlType.push(valueType); break; } if (!ret.idlType) error(`Error parsing generic type ${name.type}`); consume(">") || error(`Missing closing bracket after ${name.type}`); if (name.type === "Promise" && probe("?")) { error("Promise type cannot be nullable"); } type_suffix(ret); return ret; } function single_type(typeName) { const ret = Object.assign({ type: typeName || null }, EMPTY_IDLTYPE); const generic = generic_type(typeName); if (generic) { return Object.assign(ret, generic); } const prim = primitive_type(); let name; if (prim) { ret.idlType = prim; } else if (name = consume(ID, ...stringTypes)) { ret.idlType = name.value; if (probe("<")) error(`Unsupported generic type ${name.value}`); } else { return; } type_suffix(ret); if (ret.nullable && ret.idlType === "any") error("Type any cannot be made nullable"); return ret; } function union_type(typeName) { if (!consume("(")) return; const ret = Object.assign({ type: typeName || null }, EMPTY_IDLTYPE, { union: true, idlType: [] }); do { const typ = type_with_extended_attributes() || error("No type after open parenthesis or 'or' in union type"); ret.idlType.push(typ); } while (consume("or")); if (ret.idlType.length < 2) { error("At least two types are expected in a union type but found less"); } if (!consume(")")) error("Unterminated union type"); type_suffix(ret); return ret; } function type(typeName) { return single_type(typeName) || union_type(typeName); } function type_with_extended_attributes(typeName) { const extAttrs = extended_attrs(); const ret = single_type(typeName) || union_type(typeName); if (extAttrs.length && ret) ret.extAttrs = extAttrs; return ret; } function argument() { const start_position = consume_position; const ret = { optional: false, variadic: false, default: null }; ret.extAttrs = extended_attrs(); const opt_token = consume("optional"); if (opt_token) { ret.optional = true; } ret.idlType = type_with_extended_attributes("argument-type"); if (!ret.idlType) { unconsume(start_position); return; } if (!ret.optional && consume("...")) { ret.variadic = true; } const name = consume(ID, ...argumentNameKeywords); if (!name) { unconsume(start_position); return; } ret.name = unescape(name.value); ret.escapedName = name.value; if (ret.optional) { ret.default = default_() || null; } return ret; } function argument_list() { const ret = []; const arg = argument(); if (!arg) return ret; ret.push(arg); while (true) { if (!consume(",")) return ret; const nxt = argument() || error("Trailing comma in arguments list"); ret.push(nxt); } } function simple_extended_attr() { const name = consume(ID); if (!name) return; const ret = { name: name.value, arguments: null, type: "extended-attribute", rhs: null }; const eq = consume("="); if (eq) { ret.rhs = consume(ID, FLOAT, INT, STR); if (ret.rhs) { // No trivia exposure yet ret.rhs.trivia = undefined; } } if (consume("(")) { if (eq && !ret.rhs) { // [Exposed=(Window,Worker)] ret.rhs = { type: "identifier-list", value: identifiers() }; } else { // [NamedConstructor=Audio(DOMString src)] or [Constructor(DOMString str)] ret.arguments = argument_list(); } consume(")") || error("Unexpected token in extended attribute argument list"); } if (eq && !ret.rhs) error("No right hand side to extended attribute assignment"); return ret; } // Note: we parse something simpler than the official syntax. It's all that ever // seems to be used function extended_attrs() { const eas = []; if (!consume("[")) return eas; eas[0] = simple_extended_attr() || error("Extended attribute with not content"); while (consume(",")) { eas.push(simple_extended_attr() || error("Trailing comma in extended attribute")); } consume("]") || error("No end of extended attribute"); return eas; } function default_() { if (consume("=")) { const def = const_value(); if (def) { return def; } else if (consume("[")) { if (!consume("]")) error("Default sequence value must be empty"); return { type: "sequence", value: [] }; } else { const str = consume(STR) || error("No value for default"); str.value = str.value.slice(1, -1); // No trivia exposure yet str.trivia = undefined; return str; } } } function const_() { if (!consume("const")) return; const ret = { type: "const", nullable: false }; let typ = primitive_type(); if (!typ) { typ = consume(ID) || error("No type for const"); typ = typ.value; } ret.idlType = Object.assign({ type: "const-type" }, EMPTY_IDLTYPE, { idlType: typ }); type_suffix(ret); const name = consume(ID) || error("No name for const"); ret.name = name.value; consume("=") || error("No value assignment for const"); const cnt = const_value(); if (cnt) ret.value = cnt; else error("No value for const"); consume(";") || error("Unterminated const"); return ret; } function inheritance() { if (consume(":")) { const inh = consume(ID) || error("No type in inheritance"); return inh.value; } } function operation_rest(ret) { if (!ret) ret = {}; const name = consume(ID); ret.name = name ? unescape(name.value) : null; ret.escapedName = name ? name.value : null; consume("(") || error("Invalid operation"); ret.arguments = argument_list(); consume(")") || error("Unterminated operation"); consume(";") || error("Unterminated operation"); return ret; } function callback() { let ret; if (!consume("callback")) return; const tok = consume("interface"); if (tok) { ret = interface_rest(false, "callback interface"); return ret; } const name = consume(ID) || error("No name for callback"); ret = current = { type: "callback", name: sanitize_name(name.value, "callback") }; consume("=") || error("No assignment in callback"); ret.idlType = return_type() || error("Missing return type"); consume("(") || error("No arguments in callback"); ret.arguments = argument_list(); consume(")") || error("Unterminated callback"); consume(";") || error("Unterminated callback"); return ret; } function attribute({ noInherit = false, readonly = false } = {}) { const start_position = consume_position; const ret = { type: "attribute", static: false, stringifier: false, inherit: false, readonly: false }; if (!noInherit && consume("inherit")) { ret.inherit = true; } if (consume("readonly")) { ret.readonly = true; } else if (readonly && probe("attribute")) { error("Attributes must be readonly in this context"); } const rest = attribute_rest(ret); if (!rest) { unconsume(start_position); } return rest; } function attribute_rest(ret) { if (!consume("attribute")) { return; } ret.idlType = type_with_extended_attributes("attribute-type") || error("No type in attribute"); if (ret.idlType.generic === "sequence") error("Attributes cannot accept sequence types"); if (ret.idlType.generic === "record") error("Attributes cannot accept record types"); const name = consume(ID, "required") || error("No name in attribute"); ret.name = unescape(name.value); ret.escapedName = name.value; consume(";") || error("Unterminated attribute"); return ret; } function return_type(typeName) { const typ = type(typeName || "return-type"); if (typ) { return typ; } if (consume("void")) { return Object.assign({ type: "return-type" }, EMPTY_IDLTYPE, { idlType: "void" }); } } function operation({ regular = false } = {}) { const ret = Object.assign({}, EMPTY_OPERATION); while (!regular) { if (consume("getter")) ret.getter = true; else if (consume("setter")) ret.setter = true; else if (consume("deleter")) ret.deleter = true; else break; } ret.idlType = return_type() || error("Missing return type"); operation_rest(ret); return ret; } function static_member() { if (!consume("static")) return; const member = attribute({ noInherit: true }) || operation({ regular: true }) || error("No body in static member"); member.static = true; return member; } function stringifier() { if (!consume("stringifier")) return; if (consume(";")) { return Object.assign({}, EMPTY_OPERATION, { stringifier: true }); } const member = attribute({ noInherit: true }) || operation({ regular: true }) || error("Unterminated stringifier"); member.stringifier = true; return member; } function identifiers() { const arr = []; const id = consume(ID); if (id) { arr.push(id.value); } else error("Expected identifiers but not found"); while (true) { if (consume(",")) { const name = consume(ID) || error("Trailing comma in identifiers list"); arr.push(name.value); } else break; } return arr; } function iterable_type() { if (consume("iterable")) return "iterable"; else if (consume("legacyiterable")) return "legacyiterable"; else if (consume("maplike")) return "maplike"; else if (consume("setlike")) return "setlike"; else return; } function readonly_iterable_type() { if (consume("maplike")) return "maplike"; else if (consume("setlike")) return "setlike"; else return; } function iterable() { const start_position = consume_position; const ret = { type: null, idlType: null, readonly: false }; if (consume("readonly")) { ret.readonly = true; } const consumeItType = ret.readonly ? readonly_iterable_type : iterable_type; const ittype = consumeItType(); if (!ittype) { unconsume(start_position); return; } const secondTypeRequired = ittype === "maplike"; const secondTypeAllowed = secondTypeRequired || ittype === "iterable"; ret.type = ittype; if (ret.type !== 'maplike' && ret.type !== 'setlike') delete ret.readonly; if (consume("<")) { ret.idlType = [type_with_extended_attributes()] || error(`Error parsing ${ittype} declaration`); if (secondTypeAllowed) { if (consume(",")) { ret.idlType.push(type_with_extended_attributes()); } else if (secondTypeRequired) error(`Missing second type argument in ${ittype} declaration`); } if (!consume(">")) error(`Unterminated ${ittype} declaration`); if (!consume(";")) error(`Missing semicolon after ${ittype} declaration`); } else error(`Error parsing ${ittype} declaration`); return ret; } function interface_rest(isPartial, typeName = "interface") { const name = consume(ID) || error("No name for interface"); const mems = []; const ret = current = { type: typeName, name: isPartial ? name.value : sanitize_name(name.value, "interface"), partial: isPartial, members: mems }; if (!isPartial) ret.inheritance = inheritance() || null; consume("{") || error("Bodyless interface"); while (true) { if (consume("}")) { consume(";") || error("Missing semicolon after interface"); return ret; } const ea = extended_attrs(); const mem = const_() || static_member() || stringifier() || iterable() || attribute() || operation() || error("Unknown member"); mem.extAttrs = ea; ret.members.push(mem); } } function mixin_rest(isPartial) { if (!consume("mixin")) return; const name = consume(ID) || error("No name for interface mixin"); const mems = []; const ret = current = { type: "interface mixin", name: isPartial ? name.value : sanitize_name(name.value, "interface mixin"), partial: isPartial, members: mems }; consume("{") || error("Bodyless interface mixin"); while (true) { if (consume("}")) { consume(";") || error("Missing semicolon after interface mixin"); return ret; } const ea = extended_attrs(); const mem = const_() || stringifier() || attribute({ noInherit: true }) || operation({ regular: true }) || error("Unknown member"); mem.extAttrs = ea; ret.members.push(mem); } } function interface_(isPartial) { if (!consume("interface")) return; return mixin_rest(isPartial) || interface_rest(isPartial) || error("Interface has no proper body"); } function namespace(isPartial) { if (!consume("namespace")) return; const name = consume(ID) || error("No name for namespace"); const mems = []; const ret = current = { type: "namespace", name: isPartial ? name.value : sanitize_name(name.value, "namespace"), partial: isPartial, members: mems }; consume("{") || error("Bodyless namespace"); while (true) { if (consume("}")) { consume(";") || error("Missing semicolon after namespace"); return ret; } const ea = extended_attrs(); const mem = attribute({ noInherit: true, readonly: true }) || operation({ regular: true }) || error("Unknown member"); mem.extAttrs = ea; ret.members.push(mem); } } function partial() { if (!consume("partial")) return; const thing = dictionary(true) || interface_(true) || namespace(true) || error("Partial doesn't apply to anything"); return thing; } function dictionary(isPartial) { if (!consume("dictionary")) return; const name = consume(ID) || error("No name for dictionary"); const mems = []; const ret = current = { type: "dictionary", name: isPartial ? name.value : sanitize_name(name.value, "dictionary"), partial: isPartial, members: mems }; if (!isPartial) ret.inheritance = inheritance() || null; consume("{") || error("Bodyless dictionary"); while (true) { if (consume("}")) { consume(";") || error("Missing semicolon after dictionary"); return ret; } const ea = extended_attrs(); const required = consume("required"); const typ = type_with_extended_attributes("dictionary-type") || error("No type for dictionary member"); const name = consume(ID) || error("No name for dictionary member"); const dflt = default_() || null; if (required && dflt) error("Required member must not have a default"); const member = { type: "field", name: unescape(name.value), escapedName: name.value, required: !!required, idlType: typ, extAttrs: ea, default: dflt }; ret.members.push(member); consume(";") || error("Unterminated dictionary member"); } } function enum_() { if (!consume("enum")) return; const name = consume(ID) || error("No name for enum"); const vals = []; const ret = current = { type: "enum", name: sanitize_name(name.value, "enum"), values: vals }; consume("{") || error("No curly for enum"); let value_expected = true; while (true) { if (consume("}")) { if (!ret.values.length) error("No value in enum"); consume(";") || error("No semicolon after enum"); return ret; } else if (!value_expected) { error("No comma between enum values"); } const val = consume(STR) || error("Unexpected value in enum"); val.value = val.value.slice(1, -1); // No trivia exposure yet val.trivia = undefined; ret.values.push(val); value_expected = !!consume(","); } } function typedef() { if (!consume("typedef")) return; const ret = { type: "typedef" }; ret.idlType = type_with_extended_attributes("typedef-type") || error("No type in typedef"); const name = consume(ID) || error("No name in typedef"); ret.name = sanitize_name(name.value, "typedef"); current = ret; consume(";") || error("Unterminated typedef"); return ret; } function implements_() { const start_position = consume_position; const target = consume(ID); if (!target) return; if (consume("implements")) { const ret = { type: "implements", target: target.value }; const imp = consume(ID) || error("Incomplete implements statement"); ret.implements = imp.value; consume(";") || error("No terminating ; for implements statement"); return ret; } else { // rollback unconsume(start_position); } } function includes() { const start_position = consume_position; const target = consume(ID); if (!target) return; if (consume("includes")) { const ret = { type: "includes", target: target.value }; const imp = consume(ID) || error("Incomplete includes statement"); ret.includes = imp.value; consume(";") || error("No terminating ; for includes statement"); return ret; } else { // rollback unconsume(start_position); } } function definition() { return callback() || interface_(false) || partial() || dictionary(false) || enum_() || typedef() || implements_() || includes() || namespace(false); } function definitions() { if (!tokens.length) return []; const defs = []; while (true) { const ea = extended_attrs(); const def = definition(); if (!def) { if (ea.length) error("Stray extended attributes"); break; } def.extAttrs = ea; defs.push(def); } return defs; } const res = definitions(); if (consume_position < tokens.length) error("Unrecognised tokens"); return res; } const obj = { parse(str) { const tokens = tokenise(str); return parse(tokens); } }; if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') { module.exports = obj; } else if (typeof define === 'function' && define.amd) { define([], () => obj); } else { (self || window).WebIDL2 = obj; } })();