@@ -176,7 +176,7 @@ class FunctionNode {
176
176
throw 'Missing JS to AST parser' ;
177
177
}
178
178
179
- const ast = Object . freeze ( inParser . parse ( 'var ' + this . name + ' = ' + this . source + ';' , {
179
+ const ast = Object . freeze ( inParser . parse ( 'const ' + this . name + ' = ' + this . source + ';' , {
180
180
locations : true
181
181
} ) ) ;
182
182
if ( ast === null ) {
@@ -248,7 +248,7 @@ class FunctionNode {
248
248
for ( let i = 0 ; i < calledFunctionArguments . length ; i ++ ) {
249
249
const calledFunctionArgument = calledFunctionArguments [ i ] ;
250
250
const argument = calledFunctionArgument [ argumentIndex ] ;
251
- if ( argument !== null && argument . type !== 'Integer ' ) {
251
+ if ( argument && argument . type !== 'Integer' && argument . type !== 'LiteralInteger' && argument . type !== 'Number ') {
252
252
return argument . name ;
253
253
}
254
254
}
@@ -282,6 +282,215 @@ class FunctionNode {
282
282
} ;
283
283
}
284
284
285
+ firstAvailableTypeFromAst ( ast ) {
286
+ switch ( ast . type ) {
287
+ case 'ArrayExpression' :
288
+ return `Array(${ ast . elements . length } )` ;
289
+ case 'Literal' :
290
+ if ( Number . isInteger ( ast . value ) ) {
291
+ return 'LiteralInteger' ;
292
+ } else {
293
+ return 'Number' ;
294
+ }
295
+ case 'Identifier' :
296
+ if ( this . isAstVariable ( ast ) ) {
297
+ if ( this . getVariableSignature ( ast ) === 'value' ) {
298
+ return this . getVariableType ( ast . name )
299
+ }
300
+ }
301
+ throw this . astErrorOutput ( 'Unhandled Identifier' , ast ) ;
302
+ case 'MemberExpression' :
303
+ if ( this . isAstMathFunction ( ast ) ) {
304
+ switch ( ast . property . name ) {
305
+ case 'ceil' :
306
+ return 'Integer' ;
307
+ case 'floor' :
308
+ return 'Integer' ;
309
+ case 'round' :
310
+ return 'Integer' ;
311
+ }
312
+ return 'Number' ;
313
+ }
314
+ if ( this . isAstVariable ( ast ) ) {
315
+ const variableSignature = this . getVariableSignature ( ast ) ;
316
+ switch ( variableSignature ) {
317
+ case 'value[]' :
318
+ return typeLookupMap [ this . getVariableType ( ast . object . name ) ] ;
319
+ case 'value[][]' :
320
+ return typeLookupMap [ this . getVariableType ( ast . object . object . name ) ] ;
321
+ case 'value[][][]' :
322
+ return typeLookupMap [ this . getVariableType ( ast . object . object . object . name ) ] ;
323
+ case 'value.value' :
324
+ if ( this . isAstMathVariable ( ast ) ) {
325
+ return 'Number' ;
326
+ }
327
+ switch ( ast . property . name ) {
328
+ case 'r' :
329
+ return typeLookupMap [ this . getVariableType ( ast . object . name ) ] ;
330
+ case 'g' :
331
+ return typeLookupMap [ this . getVariableType ( ast . object . name ) ] ;
332
+ case 'b' :
333
+ return typeLookupMap [ this . getVariableType ( ast . object . name ) ] ;
334
+ case 'a' :
335
+ return typeLookupMap [ this . getVariableType ( ast . object . name ) ] ;
336
+ default :
337
+ throw this . astErrorOutput ( 'Unhandled MemberExpression' , ast ) ;
338
+ }
339
+ case 'this.thread.value' :
340
+ return 'Integer' ;
341
+ case 'this.output.value' :
342
+ return 'Integer' ;
343
+ case 'this.constants.value' :
344
+ return this . getConstantType ( ast . property . name ) ;
345
+ case 'this.constants.value[]' :
346
+ return typeLookupMap [ this . getConstantType ( ast . object . property . name ) ] ;
347
+ case 'this.constants.value[][]' :
348
+ return typeLookupMap [ this . getConstantType ( ast . object . object . property . name ) ] ;
349
+ case 'this.constants.value[][][]' :
350
+ return typeLookupMap [ this . getConstantType ( ast . object . object . object . property . name ) ] ;
351
+ }
352
+ throw this . astErrorOutput ( 'Unhandled MemberExpression' , ast ) ;
353
+ }
354
+ throw this . astErrorOutput ( 'Unhandled MemberExpression' , ast ) ;
355
+ case 'CallExpression' :
356
+ if ( this . isAstMathFunction ( ast ) ) {
357
+ return 'Number' ;
358
+ }
359
+ return ast . callee && ast . callee . name && this . lookupReturnType ? this . lookupReturnType ( ast . callee . name ) : null ;
360
+ case 'BinaryExpression' :
361
+ // modulos is Number
362
+ if ( ast . operator === '%' ) {
363
+ return 'Number' ;
364
+ }
365
+ return this . firstAvailableTypeFromAst ( ast . left ) ;
366
+ case 'UpdateExpression' :
367
+ return this . firstAvailableTypeFromAst ( ast . argument ) ;
368
+ case 'UnaryExpression' :
369
+ return this . firstAvailableTypeFromAst ( ast . argument ) ;
370
+ default :
371
+ throw this . astErrorOutput ( `Unhandled Type "${ ast . type } "` , ast ) ;
372
+ }
373
+ }
374
+
375
+ isAstMathVariable ( ast ) {
376
+ const mathProperties = [
377
+ 'E' ,
378
+ 'PI' ,
379
+ 'SQRT2' ,
380
+ 'SQRT1_2' ,
381
+ 'LN2' ,
382
+ 'LN10' ,
383
+ 'LOG2E' ,
384
+ 'LOG10E' ,
385
+ ] ;
386
+ return ast . type === 'MemberExpression' &&
387
+ ast . object && ast . object . type === 'Identifier' &&
388
+ ast . object . name === 'Math' &&
389
+ ast . property &&
390
+ ast . property . type === 'Identifier' &&
391
+ mathProperties . indexOf ( ast . property . name ) > - 1 ;
392
+ }
393
+
394
+ isAstMathFunction ( ast ) {
395
+ const mathFunctions = [
396
+ 'abs' ,
397
+ 'acos' ,
398
+ 'asin' ,
399
+ 'atan' ,
400
+ 'atan2' ,
401
+ 'ceil' ,
402
+ 'cos' ,
403
+ 'exp' ,
404
+ 'floor' ,
405
+ 'log' ,
406
+ 'log2' ,
407
+ 'max' ,
408
+ 'min' ,
409
+ 'pow' ,
410
+ 'random' ,
411
+ 'round' ,
412
+ 'sign' ,
413
+ 'sin' ,
414
+ 'sqrt' ,
415
+ 'tan' ,
416
+ ] ;
417
+ return ast . type === 'CallExpression' &&
418
+ ast . callee &&
419
+ ast . callee . type === 'MemberExpression' &&
420
+ ast . callee . object &&
421
+ ast . callee . object . type === 'Identifier' &&
422
+ ast . callee . object . name === 'Math' &&
423
+ ast . callee . property &&
424
+ ast . callee . property . type === 'Identifier' &&
425
+ mathFunctions . indexOf ( ast . callee . property . name ) > - 1 ;
426
+ }
427
+
428
+ isAstVariable ( ast ) {
429
+ return ast . type === 'Identifier' || ast . type === 'MemberExpression' ;
430
+ }
431
+
432
+ getVariableSignature ( ast ) {
433
+ if ( ! this . isAstVariable ( ast ) ) {
434
+ throw new Error ( `ast of type "${ ast . type } " is not a variable signature` ) ;
435
+ }
436
+ if ( ast . type === 'Identifier' ) {
437
+ return 'value' ;
438
+ }
439
+ const signature = [ ] ;
440
+ while ( true ) {
441
+ if ( ! ast ) break ;
442
+ if ( ast . computed ) {
443
+ signature . push ( '[]' ) ;
444
+ } else if ( ast . type === 'ThisExpression' ) {
445
+ signature . unshift ( 'this' ) ;
446
+ } else if ( ast . property && ast . property . name ) {
447
+ if (
448
+ ast . property . name === 'x' ||
449
+ ast . property . name === 'y' ||
450
+ ast . property . name === 'z'
451
+ ) {
452
+ signature . unshift ( '.value' ) ;
453
+ } else if (
454
+ ast . property . name === 'constants' ||
455
+ ast . property . name === 'thread' ||
456
+ ast . property . name === 'output'
457
+ ) {
458
+ signature . unshift ( '.' + ast . property . name ) ;
459
+ } else {
460
+ signature . unshift ( '.value' ) ;
461
+ }
462
+ } else if ( ast . name ) {
463
+ signature . unshift ( 'value' ) ;
464
+ } else {
465
+ signature . unshift ( 'unknown' ) ;
466
+ }
467
+ ast = ast . object ;
468
+ }
469
+
470
+ const signatureString = signature . join ( '' ) ;
471
+ const allowedExpressions = [
472
+ 'value' ,
473
+ 'value[]' ,
474
+ 'value[][]' ,
475
+ 'value[][][]' ,
476
+ 'value.value' ,
477
+ 'this.thread.value' ,
478
+ 'this.output.value' ,
479
+ 'this.constants.value' ,
480
+ 'this.constants.value[]' ,
481
+ 'this.constants.value[][]' ,
482
+ 'this.constants.value[][][]' ,
483
+ ] ;
484
+ if ( allowedExpressions . indexOf ( signatureString ) > - 1 ) {
485
+ return signatureString ;
486
+ }
487
+ return null ;
488
+ }
489
+
490
+ build ( ) {
491
+ return this . toString ( ) . length > 0 ;
492
+ }
493
+
285
494
/**
286
495
* @desc Parses the abstract syntax tree for generically to its respective function
287
496
* @param {Object } ast - the AST object to parse
@@ -461,23 +670,21 @@ class FunctionNode {
461
670
astArrayExpression ( ast , retArr ) {
462
671
return retArr ;
463
672
}
464
-
465
- /**
466
- * @function
467
- * @name pushParameter
468
- *
469
- * @desc [INTERNAL] pushes a source parameter onto retArr and 'casts' to int if necessary
470
- * i.e. deal with force-int-parameter state
471
- *
472
- * @param {Array } retArr - return array string
473
- * @param {String } name - the parameter name
474
- *
475
- */
476
- pushParameter ( retArr , name ) {
477
- retArr . push ( `user_${ name } ` ) ;
478
- }
479
673
}
480
674
675
+ const typeLookupMap = {
676
+ 'Array' : 'Number' ,
677
+ 'Array(2)' : 'Number' ,
678
+ 'Array(3)' : 'Number' ,
679
+ 'Array(4)' : 'Number' ,
680
+ 'Array2D' : 'Number' ,
681
+ 'Array3D' : 'Number' ,
682
+ 'HTMLImage' : 'Array(4)' ,
683
+ 'HTMLImageArray' : 'Array(4)' ,
684
+ 'NumberTexture' : 'Number' ,
685
+ 'ArrayTexture(4)' : 'Array(4)' ,
686
+ } ;
687
+
481
688
module . exports = {
482
689
FunctionNode
483
690
} ;
0 commit comments