FunctionNode.js 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. import CodeNode from './CodeNode.js';
  2. import NodeFunctionInput from './NodeFunctionInput.js';
  3. import FunctionCallNode from './FunctionCallNode.js';
  4. const declarationRegexp = /^\s*(highp|mediump|lowp)?\s*([a-z_0-9]+)\s*([a-z_0-9]+)?\s*\((.*?)\)/i;
  5. const propertiesRegexp = /[a-z_0-9]+/ig;
  6. const pragmaMain = '#pragma main';
  7. class FunctionNode extends CodeNode {
  8. constructor( code = '' ) {
  9. super( code );
  10. this.inputs = [];
  11. this.name = '';
  12. this.needsUpdate = true;
  13. this.useKeywords = true;
  14. this.presicion = '';
  15. this._includeCode = '';
  16. this._internalCode = '';
  17. }
  18. getType( /*builder*/ ) {
  19. if ( this.needsUpdate === true ) {
  20. this.parse();
  21. }
  22. return this.type;
  23. }
  24. getInputs( /*builder*/ ) {
  25. if ( this.needsUpdate === true ) {
  26. this.parse();
  27. }
  28. return this.inputs;
  29. }
  30. parse() {
  31. const code = this.code;
  32. const pragmaMainIndex = code.indexOf( pragmaMain );
  33. const mainCode = pragmaMainIndex !== - 1 ? code.substr( pragmaMainIndex + pragmaMain.length ) : code;
  34. const declaration = mainCode.match( declarationRegexp );
  35. if ( declaration !== null && declaration.length === 5 ) {
  36. // tokenizer
  37. const paramsCode = declaration[ 4 ];
  38. const propsMatches = [];
  39. let nameMatch = null;
  40. while ( ( nameMatch = propertiesRegexp.exec( paramsCode ) ) !== null ) {
  41. propsMatches.push( nameMatch );
  42. }
  43. // parser
  44. const inputs = [];
  45. let i = 0;
  46. while ( i < propsMatches.length ) {
  47. const isConst = propsMatches[ i ][ 0 ] === 'const';
  48. if ( isConst === true ) {
  49. i ++;
  50. }
  51. let qualifier = propsMatches[ i ][ 0 ];
  52. if ( qualifier === 'in' || qualifier === 'out' || qualifier === 'inout' ) {
  53. i ++;
  54. } else {
  55. qualifier = '';
  56. }
  57. const type = propsMatches[ i ++ ][ 0 ];
  58. const name = propsMatches[ i ++ ][ 0 ];
  59. inputs.push( new NodeFunctionInput( type, name, qualifier, isConst ) );
  60. }
  61. const blockCode = mainCode.substring( declaration[ 0 ].length );
  62. this.name = declaration[ 3 ] !== undefined ? declaration[ 3 ] : '';
  63. this.type = declaration[ 2 ];
  64. this.presicion = declaration[ 1 ] !== undefined ? declaration[ 1 ] : '';
  65. this.inputs = inputs;
  66. this._includeCode = pragmaMainIndex !== - 1 ? code.substr( 0, pragmaMainIndex ) : '';
  67. this._internalCode = `( ${paramsCode} ) ${blockCode}`;
  68. } else {
  69. throw new Error( 'FunctionNode: Function is not a GLSL code.' );
  70. }
  71. this.code = code;
  72. this.needsUpdate = false;
  73. }
  74. call( parameters = null ) {
  75. return new FunctionCallNode( this, parameters );
  76. }
  77. generate( builder, output ) {
  78. super.generate( builder );
  79. const type = this.getType( builder );
  80. const nodeCode = builder.getCodeFromNode( this, type );
  81. if ( this.name !== '' ) {
  82. // use a custom property name
  83. nodeCode.name = this.name;
  84. }
  85. const propertyName = builder.getPropertyName( nodeCode );
  86. const presicion = this.presicion;
  87. const includeCode = this._includeCode;
  88. let code = `${type} ${propertyName} ${this._internalCode}`;
  89. if ( presicion !== '' ) {
  90. code = `${presicion} ${code}`;
  91. }
  92. if ( includeCode !== '' ) {
  93. code = `${includeCode} ${code}`;
  94. }
  95. nodeCode.code = code;
  96. if ( output === 'property' ) {
  97. return propertyName;
  98. } else {
  99. return builder.format( `${propertyName}()`, type, output );
  100. }
  101. }
  102. }
  103. export default FunctionNode;