Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions lib/context.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class Context {
this.typedefs = new Map();
this.interfaces = new Map();
this.interfaceMixins = new Map();
this.callbackInterfaces = new Map();
this.dictionaries = new Map();
this.enumerations = new Map();

Expand All @@ -50,6 +51,9 @@ class Context {
if (this.interfaces.has(name)) {
return "interface";
}
if (this.callbackInterfaces.has(name)) {
return "callback interface";
}
if (this.dictionaries.has(name)) {
return "dictionary";
}
Expand Down
6 changes: 5 additions & 1 deletion lib/transformer.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ class Transformer {
}));

this.ctx.initialize();
const { interfaces, interfaceMixins, dictionaries, enumerations, typedefs } = this.ctx;
const { interfaces, interfaceMixins, callbackInterfaces, dictionaries, enumerations, typedefs } = this.ctx;

// first we're gathering all full interfaces and ignore partial ones
for (const file of parsed) {
Expand All @@ -108,6 +108,10 @@ class Transformer {
obj = new InterfaceMixin(this.ctx, instruction);
interfaceMixins.set(obj.name, obj);
break;
case "callback interface":
obj = { name: instruction.name }; // Not fully implemented yet.
callbackInterfaces.set(obj.name, obj);
break;
case "includes":
break; // handled later
case "dictionary":
Expand Down
57 changes: 48 additions & 9 deletions lib/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,13 @@ function generateTypeConversion(ctx, name, idlType, argAttrs = [], parentName, e
fn = `exports.convert`;
}
generateGeneric(fn);
} else if (ctx.typeOf(idlType.idlType) === "callback interface") {
// We do not save the callback context yet.
str += `
if (!utils.isObject(${name})) {
throw new TypeError(${errPrefix} + " is not an object");
}
`;
} else {
// unknown
// Try to get the impl anyway.
Expand Down Expand Up @@ -205,7 +212,7 @@ function generateTypeConversion(ctx, name, idlType, argAttrs = [], parentName, e
output.push(`if (typeof ${name} === "function") {}`);
}

if (union.sequenceLike || union.dictionary || union.record || union.object) {
if (union.sequenceLike || union.dictionary || union.record || union.object || union.callbackInterface) {
let code = `if (utils.isObject(${name})) {`;

if (union.sequenceLike) {
Expand All @@ -217,10 +224,19 @@ function generateTypeConversion(ctx, name, idlType, argAttrs = [], parentName, e
code += `} else {`;
}

if (union.dictionary || union.record) {
const prop = union.dictionary ? "dictionary" : "record";
const conv = generateTypeConversion(ctx, name, union[prop], [], parentName,
`${errPrefix} + " ${prop}"`);
if (union.dictionary) {
const conv = generateTypeConversion(ctx, name, union.dictionary, [], parentName,
`${errPrefix} + " dictionary"`);
requires.merge(conv.requires);
code += conv.body;
} else if (union.record) {
const conv = generateTypeConversion(ctx, name, union.record, [], parentName,
`${errPrefix} + " record"`);
requires.merge(conv.requires);
code += conv.body;
} else if (union.callbackInterface) {
const conv = generateTypeConversion(ctx, name, union.callbackInterface, [], parentName,
`${errPrefix} + " callback interface"`);
requires.merge(conv.requires);
code += conv.body;
} else if (union.object) {
Expand Down Expand Up @@ -381,7 +397,7 @@ function extractUnionInfo(ctx, idlType, errPrefix) {
sequenceLike: null,
record: null,
get dictionaryLike() {
return this.dictionary !== null || this.record !== null;
return this.dictionary !== null || this.record !== null || this.callbackInterface !== null;
},
ArrayBuffer: false,
ArrayBufferViews: new Set(),
Expand All @@ -395,6 +411,7 @@ function extractUnionInfo(ctx, idlType, errPrefix) {
// Callback function, not interface
callback: false,
dictionary: null,
callbackInterface: null,
interfaces: new Set(),
get interfaceLike() {
return this.interfaces.size > 0 || this.BufferSource;
Expand All @@ -408,7 +425,13 @@ function extractUnionInfo(ctx, idlType, errPrefix) {
}
seen.sequenceLike = item;
} else if (item.generic === "record") {
if (seen.record || seen.dictionary) {
if (seen.object) {
error("Dictionary-like types are not distinguishable with object type");
}
if (seen.callback) {
error("Dictionary-like types are not distinguishable with callback functions");
}
if (seen.dictionaryLike) {
error("There can only be one dictionary-like type in a union type");
}
seen.record = item;
Expand Down Expand Up @@ -474,6 +497,17 @@ function extractUnionInfo(ctx, idlType, errPrefix) {
error("There can only be one dictionary-like type in a union type");
}
seen.dictionary = item;
} else if (ctx.callbackInterfaces.has(item.idlType)) {
if (seen.object) {
error("Dictionary-like types are not distinguishable with object type");
}
if (seen.callback) {
error("Dictionary-like types are not distinguishable with callback functions");
}
if (seen.dictionaryLike) {
error("There can only be one dictionary-like type in a union type");
}
seen.callbackInterface = item.idlType;
} else if (ctx.interfaces.has(item.idlType)) {
if (seen.object) {
error("Interface types are not distinguishable with object type");
Expand Down Expand Up @@ -570,6 +604,7 @@ function sameType(ctx, type1, type2) {
sameType(ctx, extracted1.dictionary, extracted2.dictionary) &&
JSON.stringify([...extracted1.interfaces].sort()) ===
JSON.stringify([...extracted2.interfaces].sort()) &&
extracted1.callbackInterface === extracted2.callbackInterface &&
extracted1.unknown === extracted2.unknown;
}

Expand Down Expand Up @@ -621,8 +656,12 @@ function areDistinguishable(ctx, type1, type2) {
bufferSourceTypes.has(inner1.idlType);
const isInterfaceLike2 = ctx.interfaces.has(inner2.idlType) ||
bufferSourceTypes.has(inner2.idlType);
const isDictionaryLike1 = ctx.dictionaries.has(inner1.idlType) || inner1.generic === "record";
const isDictionaryLike2 = ctx.dictionaries.has(inner2.idlType) || inner2.generic === "record";
const isDictionaryLike1 = ctx.dictionaries.has(inner1.idlType) ||
ctx.callbackInterfaces.has(inner1.idlType) ||
inner1.generic === "record";
const isDictionaryLike2 = ctx.dictionaries.has(inner2.idlType) ||
ctx.callbackInterfaces.has(inner2.idlType) ||
inner2.generic === "record";
const isSequenceLike1 = inner1.generic === "sequence" || inner1.generic === "FrozenArray";
const isSequenceLike2 = inner2.generic === "sequence" || inner2.generic === "FrozenArray";

Expand Down
Loading