Skip to content

Commit 7a3d45a

Browse files
committed
fix arguments tree for object arguments
1 parent 330a916 commit 7a3d45a

File tree

1 file changed

+64
-39
lines changed

1 file changed

+64
-39
lines changed

src/core/error_helpers.js

Lines changed: 64 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -94,12 +94,19 @@ if (typeof IS_MINIFIED !== 'undefined') {
9494
// for e.g.: background(color) , where color is a p5.Color object
9595
const p5Types = [];
9696
const p5TypesNames = [];
97-
for (let key of Object.keys(p5)) {
98-
if (typeof p5[key] === 'function' && key[0] !== key[0].toLowerCase()) {
99-
p5Types.push(p5[key]);
100-
p5TypesNames.push(key);
97+
const funcSpecificp5Types = {};
98+
const funcSpecificp5Names = {};
99+
window.addEventListener('load', () => {
100+
// Make a list of all p5 classes to be used for argument validation
101+
// This must be done only when everything has loaded otherwise we get
102+
// an empty array
103+
for (let key of Object.keys(p5)) {
104+
if (typeof p5[key] === 'function' && key[0] !== key[0].toLowerCase()) {
105+
p5Types.push(p5[key]);
106+
p5TypesNames.push(key);
107+
}
101108
}
102-
}
109+
});
103110

104111
const friendlyWelcome = () => {
105112
// p5.js brand - magenta: #ED225D
@@ -288,12 +295,12 @@ if (typeof IS_MINIFIED !== 'undefined') {
288295
// into the argument tree. It stores the types of arguments that each
289296
// function has seen so far. It is used to query if a sequence of
290297
// arguments seen in validate parameters was seen before.
291-
// Lets consider the following segment of code runs repeatedly, perhaps in
292-
// a loop or in draw()
298+
// Lets consider that the following segment of code runs repeatedly, perhaps
299+
// in a loop or in draw()
293300
// color(10, 10, 10);
294301
// color(10, 10);
295302
// color('r', 'g', 'b');
296-
// After the first of the segment, the argument tree looks like
303+
// After the first of run the code segment, the argument tree looks like
297304
// - color
298305
// - number
299306
// - number
@@ -313,48 +320,66 @@ if (typeof IS_MINIFIED !== 'undefined') {
313320
// These two functions would be called repeatedly over and over again,
314321
// so they need to be as optimized for performance as possible
315322

316-
const addType = (value, obj) => {
317-
// check if the value is a p5 constant and if it is, we would want the
318-
// value itself to be stored in the tree instead of the type
319-
if (constantsReverseMap[value]) {
320-
obj = obj[value] || (obj[value] = {});
321-
} else {
322-
let type = typeof value;
323-
if (basicTypes[type]) {
324-
obj = obj[type] || (obj[type] = {});
325-
} else if (value === null) {
326-
// typeof null -> "object". don't want that
327-
obj = obj['null'] || (obj['null'] = {});
323+
const addType = (value, obj, func) => {
324+
let type = typeof value;
325+
if (basicTypes[type]) {
326+
if (constantsReverseMap[value]) {
327+
// check if the value is a p5 constant and if it is, we would want the
328+
// value itself to be stored in the tree instead of the type
329+
obj = obj[value] || (obj[value] = {});
328330
} else {
329-
if (value.constructor && value.constructor.name) {
330-
obj =
331-
obj[value.constructor.name] || (obj[value.constructor.name] = {});
331+
obj = obj[type] || (obj[type] = {});
332+
}
333+
} else if (value === null) {
334+
// typeof null -> "object". don't want that
335+
obj = obj['null'] || (obj['null'] = {});
336+
} else {
337+
// objects which are instances of p5 classes have nameless constructors.
338+
// native objects have a constructor named "Object". This check
339+
// differentiates between the two so that we dont waste time finding the
340+
// p5 class if we just have a native object
341+
if (value.constructor && value.constructor.name) {
342+
obj = obj[value.constructor.name] || (obj[value.constructor.name] = {});
343+
return obj;
344+
}
345+
346+
let p5T = funcSpecificp5Types[func];
347+
let p5TN = funcSpecificp5Names[func];
348+
if (p5T === undefined) {
349+
p5T = funcSpecificp5Types[func] = [];
350+
p5TN = funcSpecificp5Names[func] = [];
351+
}
352+
for (let i = 0, len = p5T.length; i < len; ++i) {
353+
// search on the classes we have already seen
354+
if (value instanceof p5T[i]) {
355+
obj = obj[p5TN[i]] || (obj[p5TN[i]] = {});
332356
return obj;
333357
}
334-
let flag = true;
335-
for (let i = 0, len = p5Types.length; i < len; ++i) {
336-
if (value instanceof p5Types[i]) {
337-
// if the value is p5 class
338-
// for e.g p5.Vector, p5.Color etc
339-
obj = obj[p5TypesKeys[i]] || (obj[p5TypesKeys[i]] = {});
340-
flag = false;
341-
break;
342-
}
343-
}
344-
if (flag) {
345-
obj = obj[type] || (obj[type] = {});
358+
}
359+
360+
for (let i = 0, len = p5Types.length; i < len; ++i) {
361+
// if the above search didn't work, search on all p5 classes
362+
if (value instanceof p5Types[i]) {
363+
obj = obj[p5TypesNames[i]] || (obj[p5TypesNames[i]] = {});
364+
// if found, add to known classes for this function
365+
p5T.push(p5Types[i]);
366+
p5TN.push(p5TypesNames[i]);
367+
return obj;
346368
}
347369
}
370+
371+
// nothing worked, put the type as is
372+
obj = obj[type] || (obj[type] = {});
348373
}
374+
349375
return obj;
350376
};
351377
const buildArgTypeCache = (func, arr) => {
352378
// get the if an argument tree for current function already exists
353379
let obj = argumentTree[func];
354380
if (obj === undefined) {
355381
// if it doesn't, create an empty tree
356-
argumentTree[func] = {};
357-
obj = argumentTree[func];
382+
obj = argumentTree[func] = {};
358383
}
359384

360385
for (let i = 0, len = arr.length; i < len; ++i) {
@@ -366,10 +391,10 @@ if (typeof IS_MINIFIED !== 'undefined') {
366391
// (number, number, number) and (number, [number, number])
367392
obj = obj['as'] || (obj['as'] = {});
368393
for (let j = 0, lenA = value.length; j < lenA; ++j) {
369-
obj = addType(value[j], obj);
394+
obj = addType(value[j], obj, func);
370395
}
371396
} else {
372-
obj = addType(value, obj);
397+
obj = addType(value, obj, func);
373398
}
374399
}
375400
return obj;

0 commit comments

Comments
 (0)