import isBoolean from 'lodash/isBoolean' ; import isFinite from 'lodash/isFinite' ; import { AST_TOKEN_TYPES , AST_TOKEN_TYPES as SHADER_AST_TOKEN_TYPES , } from './ast/glsl-ast-node-types' ; import { BaseNode as ShaderBaseNode , DataType } from './ast/glsl-tree' ; import { AST_NODE_TYPES } from './ast/ts-ast-node-types' ; import { ArrayExpression , CallExpression , Expression , MemberExpression , } from './ast/ts-estree' ; import { dataTypeMap } from './Transformer' ; import { componentWiseFunctions , swizzling , typeCastFunctions , } from './utils/builtin-functions' ; import { compareDataTypePriority , getComponentDataTypeFromVector , } from './utils/data-type' ; import { getIdentifierFromScope } from './utils/node' ; /**
 * 根据表达式进行类型推导
 * 尽管在 TS 的基础上扩充了基础数据类型 Scalar/Vector/Matrix，但我们希望用户可以尽量少的显式声明变量类型
 */ export class DataTypeInference { public infer ( expression , scopeNode ? ) { if ( expression ?. type === AST_NODE_TYPES . Literal ) { if ( isFinite ( expression . value ) ) { return SHADER_AST_TOKEN_TYPES . Float ; } else if ( isBoolean ( expression . value ) ) { return SHADER_AST_TOKEN_TYPES . Boolean ; } } else if ( expression ?. type === AST_NODE_TYPES . ArrayExpression ) { return this . inferArrayExpression ( expression , scopeNode ) ; } else if ( expression ?. type === AST_NODE_TYPES . Identifier && scopeNode ) { const existedIdentifier = getIdentifierFromScope ( scopeNode , expression . name ) ; if ( existedIdentifier && existedIdentifier . dataType ) { return existedIdentifier . dataType ; } } else if ( expression ?. type === AST_NODE_TYPES . CallExpression ) { return this . inferCallExpression ( expression , scopeNode ) ; } else if ( expression ?. type === AST_NODE_TYPES . BinaryExpression || expression ?. type === AST_NODE_TYPES . LogicalExpression ) { return compareDataTypePriority ( this . infer ( expression . left , scopeNode ) , this . infer ( expression . right , scopeNode ) ) ; } else if ( expression ?. type === AST_NODE_TYPES . MemberExpression ) { return this . inferMemberExpression ( expression , scopeNode ) ; } else if ( expression ?. type === AST_NODE_TYPES . ConditionalExpression ) { return this . infer ( expression . consequent , scopeNode ) ; } return SHADER_AST_TOKEN_TYPES . Float ; } public inferArrayExpression ( expression , scopeNode ? ) { const elementsSize = expression . elements . length ; if ( elementsSize <= 4 ) { if ( expression . elements . every ( ( e ) => e . type === AST_NODE_TYPES . Literal && isBoolean ( e . value ) ) ) { if ( elementsSize === 1 ) { return SHADER_AST_TOKEN_TYPES . Boolean ; } else if ( elementsSize === 2 ) { return SHADER_AST_TOKEN_TYPES . Vector2Boolean ; } else if ( elementsSize === 3 ) { return SHADER_AST_TOKEN_TYPES . Vector3Boolean ; } else if ( elementsSize === 4 ) { return SHADER_AST_TOKEN_TYPES . Vector4Boolean ; } } else { if ( elementsSize === 1 ) { return SHADER_AST_TOKEN_TYPES . Float ; } else if ( elementsSize === 2 ) { return SHADER_AST_TOKEN_TYPES . Vector2Float ; } else if ( elementsSize === 3 ) { return SHADER_AST_TOKEN_TYPES . Vector3Float ; } else if ( elementsSize === 4 ) { return SHADER_AST_TOKEN_TYPES . Vector4Float ; } } } else if ( elementsSize === 9 ) { return SHADER_AST_TOKEN_TYPES . Matrix3x3Float ; } else if ( elementsSize === 16 ) { return SHADER_AST_TOKEN_TYPES . Matrix4x4Float ; } return SHADER_AST_TOKEN_TYPES . Float ; } public inferCallExpression ( expression , scopeNode ? ) { if ( expression . callee . type === AST_NODE_TYPES . Identifier && scopeNode ) { const id = getIdentifierFromScope ( scopeNode , expression . callee . name , true ) ; if ( id ) { return id . dataType ; } } else if ( expression . callee . type === AST_NODE_TYPES . MemberExpression && expression . callee . object . type === AST_NODE_TYPES . Identifier && expression . callee . object . name === 'this' ) { return this . infer ( expression . callee . property , scopeNode ) ; } if ( expression . callee . type === AST_NODE_TYPES . Identifier ) { if ( typeCastFunctions . indexOf ( expression . callee . name ) > - 1 ) { return dataTypeMap [ expression . callee . name ] ; } else if ( componentWiseFunctions . indexOf ( expression . callee . name ) > - 1 ) { if ( expression . arguments . length ) { return this . infer ( expression . arguments [ 0 ] , scopeNode ) ; } } } return SHADER_AST_TOKEN_TYPES . Float ; } public inferMemberExpression ( expression , scopeNode ? ) { if ( expression . object . type === AST_NODE_TYPES . Identifier && expression . object . name === 'this' ) { return this . infer ( expression . property , scopeNode ) ; } const objectType = this . infer ( expression . object , scopeNode ) ; if ( ! expression . computed ) { if ( expression . property . type === AST_NODE_TYPES . Identifier ) { const propertySize = expression . property . name . length ; if ( propertySize <= 4 && expression . property . name . split ( '' ) . every ( ( p ) => swizzling . indexOf ( p ) > - 1 ) ) { if ( propertySize === 1 ) { return getComponentDataTypeFromVector ( objectType ) ; } else { if ( objectType === AST_TOKEN_TYPES . Vector2Float || objectType === AST_TOKEN_TYPES . Vector3Float || objectType === AST_TOKEN_TYPES . Vector4Float ) { if ( propertySize === 2 ) { return AST_TOKEN_TYPES . Vector2Float ; } else if ( propertySize === 3 ) { return AST_TOKEN_TYPES . Vector3Float ; } else if ( propertySize === 4 ) { return AST_TOKEN_TYPES . Vector4Float ; } } else if ( objectType === AST_TOKEN_TYPES . Vector2Int || objectType === AST_TOKEN_TYPES . Vector3Int || objectType === AST_TOKEN_TYPES . Vector4Int ) { if ( propertySize === 2 ) { return AST_TOKEN_TYPES . Vector2Int ; } else if ( propertySize === 3 ) { return AST_TOKEN_TYPES . Vector3Int ; } else if ( propertySize === 4 ) { return AST_TOKEN_TYPES . Vector4Int ; } } else if ( objectType === AST_TOKEN_TYPES . Vector2Uint || objectType === AST_TOKEN_TYPES . Vector3Uint || objectType === AST_TOKEN_TYPES . Vector4Uint ) { if ( propertySize === 2 ) { return AST_TOKEN_TYPES . Vector2Uint ; } else if ( propertySize === 3 ) { return AST_TOKEN_TYPES . Vector3Uint ; } else if ( propertySize === 4 ) { return AST_TOKEN_TYPES . Vector4Uint ; } } else if ( objectType === AST_TOKEN_TYPES . Vector2Boolean || objectType === AST_TOKEN_TYPES . Vector3Boolean || objectType === AST_TOKEN_TYPES . Vector4Boolean ) { if ( propertySize === 2 ) { return AST_TOKEN_TYPES . Vector2Boolean ; } else if ( propertySize === 3 ) { return AST_TOKEN_TYPES . Vector3Boolean ; } else if ( propertySize === 4 ) { return AST_TOKEN_TYPES . Vector4Boolean ; } } } } } } else { return getComponentDataTypeFromVector ( objectType ) ; } return SHADER_AST_TOKEN_TYPES . Float ; } }