Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Type conversion overhaul #33

Merged
merged 9 commits into from
May 14, 2017
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
10 changes: 5 additions & 5 deletions lib/constructs/attribute.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ const conversions = require("webidl-conversions");

const utils = require("../utils");
const reflector = require("../reflector");
const Parameters = require("../parameters");
const Types = require("../types");

function Attribute(obj, I, idl) {
function Attribute(ctx, obj, I, idl) {
this.ctx = ctx;
this.obj = obj;
this.interface = I;
this.idl = idl;
Expand All @@ -27,10 +28,9 @@ Attribute.prototype.generate = function () {
definedOn = `obj`;
}
let getterBody = `return utils.tryWrapperForImpl(${objName}[impl].${this.idl.name});`;
let setterBody = `${objName}[impl].${this.idl.name} = utils.tryImplForWrapper(V);`;
let setterBody = `${objName}[impl].${this.idl.name} = V;`;
if (conversions[this.idl.idlType.idlType]) {
getterBody = `return ${objName}[impl].${this.idl.name};`;
setterBody = `${objName}[impl].${this.idl.name} = V;`;
}

if (this.idl.static) {
Expand All @@ -54,7 +54,7 @@ Attribute.prototype.generate = function () {
${getterBody}
},`;
if (!this.idl.readonly) {
const conv = Parameters.generateVarConversion("V", { type: this.idl.idlType, optional: false }, this.idl.extAttrs, new Set());
const conv = Types.generateTypeConversion(this.ctx, "V", this.idl.idlType, this.idl.extAttrs, this.interface.name, `"Failed to set the '${this.idl.name}' property on '${this.interface.name}': The provided value"`);
Object.assign(requires, conv.requires);
let conversion = conv.body.replace(/\n/g, "\n ");
str += `
Expand Down
3 changes: 2 additions & 1 deletion lib/constructs/constant.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"use strict";

function Constant(obj, I, idl) {
function Constant(ctx, obj, I, idl) {
this.ctx = ctx;
this.obj = obj;
this.interface = I;
this.idl = idl;
Expand Down
52 changes: 15 additions & 37 deletions lib/constructs/dictionary.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
"use strict";

const conversions = require("webidl-conversions");
const Types = require("../types");
const utils = require("../utils");

class Dictionary {
constructor(idl, opts) {
constructor(ctx, idl) {
this.ctx = ctx;
this.idl = idl;
this.name = idl.name;
this.opts = opts;
}

_generateConversions() {
Expand All @@ -32,34 +32,15 @@ class Dictionary {
this.str += `
if (value !== undefined) {`;
const argAttrs = field.extAttrs;
const enforceRange = utils.getExtAttr(argAttrs, "EnforceRange");
const clamp = utils.getExtAttr(argAttrs, "Clamp");

let optString = "";
if (clamp) {
optString = `, { clamp: true }`;
} else if (enforceRange) {
optString = `, { enforceRange: true }`;
}

let conversionFn = "";
if (conversions[typeConversion.idlType]) {
conversionFn = `conversions["${typeConversion.idlType}"]`;
} else if (this.opts.customTypes.has(typeConversion.idlType)) {
this.str = `const convert${typeConversion.idlType} = require("./${typeConversion.idlType}");\n` + this.str;
conversionFn = `convert${typeConversion.idlType}`;
const conv = Types.generateTypeConversion(this.ctx, "value", typeConversion, argAttrs, this.name, `\`\${context} has member ${field.name} that\``);
for (let key in conv.requires) {
this.str = `const ${key} = ${conv.requires[key]};\n` + this.str;
}
this.str += conv.body;
this.str += `
ret[key] = value;`

if (typeConversion.array) {
this.str += `
ret[key] = [];
for (let i = 0; i < value.length; ++i) {
ret[key][i] = ${conversionFn}(value[i]${optString});
}`;
} else {
this.str += `
ret[key] = ${conversionFn}(value${optString});`;
}
if (field.required) {
this.str += `
} else {
Expand All @@ -82,26 +63,23 @@ class Dictionary {
generate() {
this.str += `
module.exports = {
convertInherit(obj, ret) {`;
convertInherit(obj, ret, { context = "The provided value" } = {}) {`;
if (this.idl.inheritance) {
this.str = `const ${this.idl.inheritance} = require("./${this.idl.inheritance}");\n` + this.str;
this.str += `
${this.idl.inheritance}.convertInherit(obj, ret);`;
${this.idl.inheritance}.convertInherit(obj, ret, { context });`;
}
this._generateConversions();
this.str += `
},

convert(obj) {
if (obj !== undefined && typeof obj !== "object") {
throw new TypeError("Dictionary has to be an object");
}
if (obj instanceof Date || obj instanceof RegExp) {
throw new TypeError("Dictionary may not be a Date or RegExp object");
convert(obj, { context = "The provided value" } = {}) {
if (obj !== undefined && typeof obj !== "object" && typeof obj !== "function") {
throw new TypeError(\`\${context} is not an object.\`);
}

const ret = Object.create(null);
module.exports.convertInherit(obj, ret);
module.exports.convertInherit(obj, ret, { context });
return ret;
}
};`;
Expand Down
23 changes: 15 additions & 8 deletions lib/constructs/interface.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ const Overloads = require("../overloads");
const Parameters = require("../parameters");
const keywords = require("../keywords");

function Interface(idl, opts) {
function Interface(ctx, idl, opts) {
this.ctx = ctx;
this.idl = idl;
this.name = idl.name;
this.factory = !!utils.getExtAttr(this.idl.extAttrs, "WebIDL2JSFactory");
Expand Down Expand Up @@ -89,7 +90,7 @@ Interface.prototype.generateConstructor = function () {
}
}

const conversions = Parameters.generateOverloadConversions(overloads, this.opts.customTypes);
const conversions = Parameters.generateOverloadConversions(this.ctx, overloads, this.name, `Failed to construct '${this.name}': `);
Object.assign(this.requires, conversions.requires);

minConstructor.nameList = minConstructor.nameList.map((name) => (keywords.has(name) ? "_" : "") + name);
Expand Down Expand Up @@ -184,6 +185,12 @@ Interface.prototype.generateExport = function () {
}
}
return false;
},
convert(obj, { context = "The provided value" } = {}) {
if (module.exports.is(obj)) {
return utils.implForWrapper(obj);
}
throw new TypeError(\`\${context} is not of type '${this.name}'.\`);
},`;

if (this.hasPairIterator) {
Expand Down Expand Up @@ -252,7 +259,7 @@ Interface.prototype.generateIface = function () {
for (let i = 0; i < this.idl.members.length; ++i) {
const memberIdl = this.idl.members[i];
if (memberIdl.type === "attribute" && (utils.getExtAttr(memberIdl.extAttrs, "Unforgeable") || utils.isGlobal(this.idl))) {
const member = new Attribute(this, this.idl, memberIdl);
const member = new Attribute(this.ctx, this, this.idl, memberIdl);
this.str += "\n " + member.generate().body.replace(/\n/g, '\n ');
}
}
Expand Down Expand Up @@ -284,7 +291,7 @@ Interface.prototype.generateIface = function () {

this._internalSetup(obj);\n`;

const implClass = require(this.opts.implDir + "/" + this.name + this.opts.implSuffix);
const implClass = require(this.opts.implDir + "/" + this.name + this.ctx.implSuffix);
this.str += `
Object.defineProperty(obj, impl, {
value: new Impl.implementation(constructorArgs, privateData),
Expand Down Expand Up @@ -313,14 +320,14 @@ Interface.prototype.generateOperations = function () {

switch (memberIdl.type) {
case "operation":
member = new Operation(this, this.idl, memberIdl, { customTypes: this.opts.customTypes });
member = new Operation(this.ctx, this, this.idl, memberIdl);
if (done[member.name]) {
continue;
}
done[member.name] = true;
break;
case "iterable":
member = new Iterable(this, this.idl, memberIdl, { customTypes: this.opts.customTypes });
member = new Iterable(this.ctx, this, this.idl, memberIdl);
break;
default:
//throw new Error("Can't handle member of type '" + memberIdl.type + "'");
Expand All @@ -345,10 +352,10 @@ Interface.prototype.generateAttributes = function () {
if (utils.getExtAttr(memberIdl.extAttrs, "Unforgeable") || utils.isGlobal(this.idl)) {
break;
}
member = new Attribute(this, this.idl, memberIdl);
member = new Attribute(this.ctx, this, this.idl, memberIdl);
break;
case "const":
member = new Constant(this, this.idl, memberIdl);
member = new Constant(this.ctx, this, this.idl, memberIdl);
break;
default:
//throw new Error("Can't handle member of type '" + memberIdl.type + "'");
Expand Down
4 changes: 2 additions & 2 deletions lib/constructs/iterable.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ const conversions = require("webidl-conversions");
const keywords = require("../keywords");
const utils = require("../utils");

function Iterable(obj, I, idl, opts) {
function Iterable(ctx, obj, I, idl) {
this.ctx = ctx;
this.obj = obj;
this.interface = I;
this.idl = idl;
this.name = idl.type;
this.opts = opts;
}

Iterable.prototype.generateFunction = function (key, kind, keyExpr, fnName) {
Expand Down
5 changes: 3 additions & 2 deletions lib/constructs/operation.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ const Overloads = require("../overloads");
const Parameters = require("../parameters");
const keywords = require("../keywords");

function Operation(obj, I, idl) {
function Operation(ctx, obj, I, idl) {
this.ctx = ctx;
this.obj = obj;
this.interface = I;
this.idl = idl;
Expand Down Expand Up @@ -52,7 +53,7 @@ Operation.prototype.generate = function () {

const callOn = this.idl.static ? "Impl" : "this[impl]";

const parameterConversions = Parameters.generateOverloadConversions(overloads, this.obj.opts.customTypes);
const parameterConversions = Parameters.generateOverloadConversions(this.ctx, overloads, this.interface.name, `Failed to execute '${name}' on '${this.obj.name}': `);
const argsSpread = parameterConversions.hasArgs ? "...args" : "";
Object.assign(requires, parameterConversions.requires);
str += parameterConversions.body;
Expand Down
16 changes: 16 additions & 0 deletions lib/context.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"use strict";

class Context {
constructor({ implSuffix = "" } = {}) {
this.implSuffix = implSuffix;
this.initialize();
}

initialize() {
this.customTypes = new Map();
this.interfaces = Object.create(null);
this.dictionaries = Object.create(null);
}
}

module.exports = Context;
5 changes: 3 additions & 2 deletions lib/overloads.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ module.exports.getEffectiveOverloads = function (A, N, I, C) {
return S;
};

module.exports.proveSimiliarity = function (overloads) {
module.exports.proveSimiliarity = function (ctx, overloads) {
let maxArguments = overloads[0].nameList.length;
for (let i = 1; i < overloads.length; ++i) {
if (overloads[i].nameList.length > maxArguments) {
Expand Down Expand Up @@ -93,11 +93,12 @@ module.exports.proveSimiliarity = function (overloads) {
if (maybeType.type.idlType !== thisType.idlType || maybeType.type.array !== thisType.array ||
maybeType.default !== overloads[j].operation.arguments[i].default) {
maybeType = null;
break;
}
}

typeConversions.push(maybeType);
}

return typeConversions;
};
};
Loading