var error = function (str) { var tok = "", numTokens = 0, maxTokens = 5; while (numTokens < maxTokens && tokens.length > numTokens) {
tok += tokens[numTokens].value;
numTokens++;
} thrownew WebIDLParseError(str, line, tok, tokens.slice(0, 5));
};
var last_token = null;
var consume = function (type, value) { if (!tokens.length || tokens[0].type !== type) return; if (typeof value === "undefined" || tokens[0].value === value) {
last_token = tokens.shift(); if (type === ID) last_token.value = last_token.value.replace(/^_/, ""); return last_token;
}
};
var ws = function () { if (!tokens.length) return; if (tokens[0].type === "whitespace") { var t = tokens.shift();
t.value.replace(/\n/g, function (m) { line++; return m; }); return t;
}
};
var all_ws = function (store, pea) { // pea == post extended attribute, tpea = same for types var t = { type: "whitespace", value: "" }; while (true) { var w = ws(); if (!w) break;
t.value += w.value;
} if (t.value.length > 0) { if (store) { var w = t.value
, re = { "ws": /^([\t\n\r ]+)/
, "line-comment": /^\/\/(.*)\n?/m
, "multiline-comment": /^\/\*((?:.|\n|\r)*?)\*\//
}
, wsTypes = []
; for (var k in re) wsTypes.push(k); while (w.length) { var matched = false; for (var i = 0, n = wsTypes.length; i < n; i++) { var type = wsTypes[i];
w = w.replace(re[type], function (tok, m1) {
store.push({ type: type + (pea ? ("-" + pea) : ""), value: m1 });
matched = true; return"";
}); if (matched) break;
} if (matched) continue; thrownew Error("Surprising white space construct."); // this shouldn't happen
}
} return t;
}
};
var integer_type = function () { var ret = "";
all_ws(); if (consume(ID, "unsigned")) ret = "unsigned ";
all_ws(); if (consume(ID, "short")) return ret + "short"; if (consume(ID, "long")) {
ret += "long";
all_ws(); if (consume(ID, "long")) return ret + " long"; return ret;
} if (ret) error("Failed to parse integer type");
};
var float_type = function () { var ret = "";
all_ws(); if (consume(ID, "unrestricted")) ret = "unrestricted ";
all_ws(); if (consume(ID, "float")) return ret + "float"; if (consume(ID, "double")) return ret + "double"; if (ret) error("Failed to parse float type");
};
var primitive_type = function () { var num_type = integer_type() || float_type(); if (num_type) return num_type;
all_ws(); if (consume(ID, "boolean")) return"boolean"; if (consume(ID, "byte")) return"byte"; if (consume(ID, "octet")) return"octet";
};
var const_value = function () { if (consume(ID, "true")) return { type: "boolean", value: true }; if (consume(ID, "false")) return { type: "boolean", value: false }; if (consume(ID, "null")) return { type: "null" }; if (consume(ID, "Infinity")) return { type: "Infinity", negative: false }; if (consume(ID, "NaN")) return { type: "NaN" }; var ret = consume(FLOAT) || consume(INT); if (ret) return { type: "number", value: 1 * ret.value }; var tok = consume(OTHER, "-"); if (tok) { if (consume(ID, "Infinity")) return { type: "Infinity", negative: true }; else tokens.unshift(tok);
}
};
var type_suffix = function (obj) { while (true) {
all_ws(); if (consume(OTHER, "?")) { if (obj.nullable) error("Can't nullable more than once");
obj.nullable = true;
} elseif (consume(OTHER, "[")) {
all_ws();
consume(OTHER, "]") || error("Unterminated array type"); if (!obj.array) {
obj.array = 1;
obj.nullableArray = [obj.nullable];
} else {
obj.array++;
obj.nullableArray.push(obj.nullable);
}
obj.nullable = false;
} elsereturn;
}
};
var single_type = function () { var prim = primitive_type()
, ret = { sequence: false, generic: null, nullable: false, array: false, union: false }
, name
, value
; if (prim) {
ret.idlType = prim;
} elseif (name = consume(ID)) {
value = name.value;
all_ws(); // Generic types if (consume(OTHER, "<")) { // backwards compat if (value === "sequence") {
ret.sequence = true;
}
ret.generic = value;
ret.idlType = type() || error("Error parsing generic type " + value);
all_ws(); if (!consume(OTHER, ">")) error("Unterminated generic type " + value);
all_ws(); if (consume(OTHER, "?")) ret.nullable = true; return ret;
} else {
ret.idlType = value;
}
} else { return;
}
type_suffix(ret); if (ret.nullable && !ret.array && ret.idlType === "any") error("Type any cannot be made nullable"); return ret;
};
var union_type = function () {
all_ws(); if (!consume(OTHER, "(")) return; var ret = { sequence: false, generic: null, nullable: false, array: false, union: true, idlType: [] }; var fst = type() || error("Union type with no content");
ret.idlType.push(fst); while (true) {
all_ws(); if (!consume(ID, "or")) break; var typ = type() || error("No type after 'or' in union type");
ret.idlType.push(typ);
} if (!consume(OTHER, ")")) error("Unterminated union type");
type_suffix(ret); return ret;
};
var type = function () { return single_type() || union_type();
};
var argument = function (store) { var ret = { optional: false, variadic: false };
ret.extAttrs = extended_attrs(store);
all_ws(store, "pea"); var opt_token = consume(ID, "optional"); if (opt_token) {
ret.optional = true;
all_ws();
}
ret.idlType = type(); if (!ret.idlType) { if (opt_token) tokens.unshift(opt_token); return;
} var type_token = last_token; if (!ret.optional) {
all_ws(); if (tokens.length >= 3 &&
tokens[0].type === "other" && tokens[0].value === "." &&
tokens[1].type === "other" && tokens[1].value === "." &&
tokens[2].type === "other" && tokens[2].value === "."
) {
tokens.shift();
tokens.shift();
tokens.shift();
ret.variadic = true;
}
}
all_ws(); var name = consume(ID); if (!name) { if (opt_token) tokens.unshift(opt_token);
tokens.unshift(type_token); return;
}
ret.name = name.value; if (ret.optional) {
all_ws();
ret["default"] = default_();
} return ret;
};
var argument_list = function (store) { var ret = []
, arg = argument(store ? ret : null)
; if (!arg) return;
ret.push(arg); while (true) {
all_ws(store ? ret : null); if (!consume(OTHER, ",")) return ret; var nxt = argument(store ? ret : null) || error("Trailing comma in arguments list");
ret.push(nxt);
}
};
var type_pair = function () {
all_ws(); var k = type(); if (!k) return;
all_ws() if (!consume(OTHER, ",")) return;
all_ws(); var v = type(); if (!v) return; return [k, v];
};
var simple_extended_attr = function (store) {
all_ws(); var name = consume(ID); if (!name) return; var ret = {
name: name.value
, "arguments": null
};
all_ws(); var eq = consume(OTHER, "="); if (eq) {
all_ws();
ret.rhs = consume(ID); if (!ret.rhs) return error("No right hand side to extended attribute assignment");
}
all_ws(); if (consume(OTHER, "(")) { var args, pair; // [Constructor(DOMString str)] if (args = argument_list(store)) {
ret["arguments"] = args;
} // [MapClass(DOMString, DOMString)] elseif (pair = type_pair()) {
ret.typePair = pair;
} // [Constructor()] else {
ret["arguments"] = [];
}
all_ws();
consume(OTHER, ")") || error("Unexpected token in extended attribute argument list or type pair");
} return ret;
};
// Note: we parse something simpler than the official syntax. It's all that ever // seems to be used var extended_attrs = function (store) { var eas = [];
all_ws(store); if (!consume(OTHER, "[")) return eas;
eas[0] = simple_extended_attr(store) || error("Extended attribute with not content");
all_ws(); while (consume(OTHER, ",")) {
eas.push(simple_extended_attr(store) || error("Trailing comma in extended attribute"));
all_ws();
}
consume(OTHER, "]") || error("No end of extended attribute"); return eas;
};
var default_ = function () {
all_ws(); if (consume(OTHER, "=")) {
all_ws(); var def = const_value(); if (def) { return def;
} else { var str = consume(STR) || error("No value for default");
str.value = str.value.replace(/^"/, "").replace(/"$/, ""); return str;
}
}
};
var const_ = function (store) {
all_ws(store, "pea"); if (!consume(ID, "const")) return; var ret = { type: "const", nullable: false };
all_ws(); var typ = primitive_type(); if (!typ) {
typ = consume(ID) || error("No type for const");
typ = typ.value;
}
ret.idlType = typ;
all_ws(); if (consume(OTHER, "?")) {
ret.nullable = true;
all_ws();
} var name = consume(ID) || error("No name for const");
ret.name = name.value;
all_ws();
consume(OTHER, "=") || error("No value assignment for const");
all_ws(); var cnt = const_value(); if (cnt) ret.value = cnt; else error("No value for const");
all_ws();
consume(OTHER, ";") || error("Unterminated const"); return ret;
};
var inheritance = function () {
all_ws(); if (consume(OTHER, ":")) {
all_ws(); var inh = consume(ID) || error ("No type in inheritance"); return inh.value;
}
};
var operation_rest = function (ret, store) {
all_ws(); if (!ret) ret = {}; var name = consume(ID);
ret.name = name ? name.value : null;
all_ws();
consume(OTHER, "(") || error("Invalid operation");
ret["arguments"] = argument_list(store) || [];
all_ws();
consume(OTHER, ")") || error("Unterminated operation");
all_ws();
consume(OTHER, ";") || error("Unterminated operation"); return ret;
};
var callback = function (store) {
all_ws(store, "pea"); var ret; if (!consume(ID, "callback")) return;
all_ws(); var tok = consume(ID, "interface"); if (tok) {
tokens.unshift(tok);
ret = interface_();
ret.type = "callback interface"; return ret;
} var name = consume(ID) || error("No name for callback");
ret = { type: "callback", name: name.value };
all_ws();
consume(OTHER, "=") || error("No assignment in callback");
all_ws();
ret.idlType = return_type();
all_ws();
consume(OTHER, "(") || error("No arguments in callback");
ret["arguments"] = argument_list(store) || [];
all_ws();
consume(OTHER, ")") || error("Unterminated callback");
all_ws();
consume(OTHER, ";") || error("Unterminated callback"); return ret;
};
var attribute = function (store) {
all_ws(store, "pea"); var grabbed = []
, ret = {
type: "attribute"
, "static": false
, stringifier: false
, inherit: false
, readonly: false
}; if (consume(ID, "static")) {
ret["static"] = true;
grabbed.push(last_token);
} elseif (consume(ID, "stringifier")) {
ret.stringifier = true;
grabbed.push(last_token);
} var w = all_ws(); if (w) grabbed.push(w); if (consume(ID, "inherit")) { if (ret["static"] || ret.stringifier) error("Cannot have a static or stringifier inherit");
ret.inherit = true;
grabbed.push(last_token); var w = all_ws(); if (w) grabbed.push(w);
} if (consume(ID, "readonly")) {
ret.readonly = true;
grabbed.push(last_token); var w = all_ws(); if (w) grabbed.push(w);
} if (!consume(ID, "attribute")) {
tokens = grabbed.concat(tokens); return;
}
all_ws();
ret.idlType = type() || error("No type in attribute"); if (ret.idlType.sequence) error("Attributes cannot accept sequence types");
all_ws(); var name = consume(ID) || error("No name in attribute");
ret.name = name.value;
all_ws();
consume(OTHER, ";") || error("Unterminated attribute"); return ret;
};
var return_type = function () { var typ = type(); if (!typ) { if (consume(ID, "void")) { return"void";
} else error("No return type");
} return typ;
};
var identifiers = function (arr) { while (true) {
all_ws(); if (consume(OTHER, ",")) {
all_ws(); var name = consume(ID) || error("Trailing comma in identifiers list");
arr.push(name.value);
} elsebreak;
}
};
var serialiser = function (store) {
all_ws(store, "pea"); if (!consume(ID, "serializer")) return; var ret = { type: "serializer" };
all_ws(); if (consume(OTHER, "=")) {
all_ws(); if (consume(OTHER, "{")) {
ret.patternMap = true;
all_ws(); var id = consume(ID); if (id && id.value === "getter") {
ret.names = ["getter"];
} elseif (id && id.value === "inherit") {
ret.names = ["inherit"];
identifiers(ret.names);
} elseif (id) {
ret.names = [id.value];
identifiers(ret.names);
} else {
ret.names = [];
}
all_ws();
consume(OTHER, "}") || error("Unterminated serializer pattern map");
} elseif (consume(OTHER, "[")) {
ret.patternList = true;
all_ws(); var id = consume(ID); if (id && id.value === "getter") {
ret.names = ["getter"];
} elseif (id) {
ret.names = [id.value];
identifiers(ret.names);
} else {
ret.names = [];
}
all_ws();
consume(OTHER, "]") || error("Unterminated serializer pattern list");
} else { var name = consume(ID) || error("Invalid serializer");
ret.name = name.value;
}
all_ws();
consume(OTHER, ";") || error("Unterminated serializer"); return ret;
} elseif (consume(OTHER, ";")) { // noop, just parsing
} else {
ret.idlType = return_type();
all_ws();
ret.operation = operation_rest(null, store);
} return ret;
};
var interface_ = function (isPartial, store) {
all_ws(isPartial ? null : store, "pea"); if (!consume(ID, "interface")) return;
all_ws(); var name = consume(ID) || error("No name for interface"); var mems = []
, ret = {
type: "interface"
, name: name.value
, partial: false
, members: mems
}; if (!isPartial) ret.inheritance = inheritance() || null;
all_ws();
consume(OTHER, "{") || error("Bodyless interface"); while (true) {
all_ws(store ? mems : null); if (consume(OTHER, "}")) {
all_ws();
consume(OTHER, ";") || error("Missing semicolon after interface"); return ret;
} var ea = extended_attrs(store ? mems : null);
all_ws(); var cnt = const_(store ? mems : null); if (cnt) {
cnt.extAttrs = ea;
ret.members.push(cnt); continue;
} var mem = serialiser(store ? mems : null) ||
attribute(store ? mems : null) ||
operation(store ? mems : null) ||
error("Unknown member");
mem.extAttrs = ea;
ret.members.push(mem);
}
};
var partial = function (store) {
all_ws(store, "pea"); if (!consume(ID, "partial")) return; var thing = dictionary(true, store) ||
interface_(true, store) ||
error("Partial doesn't apply to anything");
thing.partial = true; return thing;
};
var dictionary = function (isPartial, store) {
all_ws(isPartial ? null : store, "pea"); if (!consume(ID, "dictionary")) return;
all_ws(); var name = consume(ID) || error("No name for dictionary"); var mems = []
, ret = {
type: "dictionary"
, name: name.value
, partial: false
, members: mems
}; if (!isPartial) ret.inheritance = inheritance() || null;
all_ws();
consume(OTHER, "{") || error("Bodyless dictionary"); while (true) {
all_ws(store ? mems : null); if (consume(OTHER, "}")) {
all_ws();
consume(OTHER, ";") || error("Missing semicolon after dictionary"); return ret;
} var ea = extended_attrs(store ? mems : null);
all_ws(store ? mems : null, "pea"); var typ = type() || error("No type for dictionary member");
all_ws(); var name = consume(ID) || error("No name for dictionary member");
ret.members.push({
type: "field"
, name: name.value
, idlType: typ
, extAttrs: ea
, "default": default_()
});
all_ws();
consume(OTHER, ";") || error("Unterminated dictionary member");
}
};
var exception = function (store) {
all_ws(store, "pea"); if (!consume(ID, "exception")) return;
all_ws(); var name = consume(ID) || error("No name for exception"); var mems = []
, ret = {
type: "exception"
, name: name.value
, members: mems
};
ret.inheritance = inheritance() || null;
all_ws();
consume(OTHER, "{") || error("Bodyless exception"); while (true) {
all_ws(store ? mems : null); if (consume(OTHER, "}")) {
all_ws();
consume(OTHER, ";") || error("Missing semicolon after exception"); return ret;
} var ea = extended_attrs(store ? mems : null);
all_ws(store ? mems : null, "pea"); var cnt = const_(); if (cnt) {
cnt.extAttrs = ea;
ret.members.push(cnt);
} else { var typ = type();
all_ws(); var name = consume(ID);
all_ws(); if (!typ || !name || !consume(OTHER, ";")) error("Unknown member in exception body");
ret.members.push({
type: "field"
, name: name.value
, idlType: typ
, extAttrs: ea
});
}
}
};
var enum_ = function (store) {
all_ws(store, "pea"); if (!consume(ID, "enum")) return;
all_ws(); var name = consume(ID) || error("No name for enum"); var vals = []
, ret = {
type: "enum"
, name: name.value
, values: vals
};
all_ws();
consume(OTHER, "{") || error("No curly for enum"); var saw_comma = false; while (true) {
all_ws(store ? vals : null); if (consume(OTHER, "}")) {
all_ws(); if (saw_comma) error("Trailing comma in enum");
consume(OTHER, ";") || error("No semicolon after enum"); return ret;
} var val = consume(STR) || error("Unexpected value in enum");
ret.values.push(val.value.replace(/"/g, ""));
all_ws(store ? vals : null); if (consume(OTHER, ",")) { if (store) vals.push({ type: "," });
all_ws(store ? vals : null);
saw_comma = true;
} else {
saw_comma = false;
}
}
};
var typedef = function (store) {
all_ws(store, "pea"); if (!consume(ID, "typedef")) return; var ret = {
type: "typedef"
};
all_ws();
ret.typeExtAttrs = extended_attrs();
all_ws(store, "tpea");
ret.idlType = type() || error("No type in typedef");
all_ws(); var name = consume(ID) || error("No name in typedef");
ret.name = name.value;
all_ws();
consume(OTHER, ";") || error("Unterminated typedef"); return ret;
};
var implements_ = function (store) {
all_ws(store, "pea"); var target = consume(ID); if (!target) return; var w = all_ws(); if (consume(ID, "implements")) { var ret = {
type: "implements"
, target: target.value
};
all_ws(); var imp = consume(ID) || error("Incomplete implements statement");
ret["implements"] = imp.value;
all_ws();
consume(OTHER, ";") || error("No terminating ; for implements statement"); return ret;
} else { // rollback
tokens.unshift(w);
tokens.unshift(target);
}
};
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.