import { TempNode } from './TempNode.js'; import { NodeLib } from './NodeLib.js'; const declarationRegexp = /^\s*([a-z_0-9]+)\s+([a-z_0-9]+)\s*\(([\s\S]*?)\)/i, propertiesRegexp = /[a-z_0-9]+/ig; class FunctionNode extends TempNode { constructor( src, includes, extensions, keywords, type ) { super( type ); this.isMethod = type === undefined; this.isInterface = false; this.parse( src, includes, extensions, keywords ); } getShared( /* builder, output */ ) { return ! this.isMethod; } getType( builder ) { return builder.getTypeByFormat( this.type ); } getInputByName( name ) { let i = this.inputs.length; while ( i -- ) { if ( this.inputs[ i ].name === name ) { return this.inputs[ i ]; } } } getIncludeByName( name ) { let i = this.includes.length; while ( i -- ) { if ( this.includes[ i ].name === name ) { return this.includes[ i ]; } } } generate( builder, output ) { let match, offset = 0, src = this.src; for ( let i = 0; i < this.includes.length; i ++ ) { builder.include( this.includes[ i ], this ); } for ( const ext in this.extensions ) { builder.extensions[ ext ] = true; } const matches = []; while ( match = propertiesRegexp.exec( this.src ) ) matches.push( match ); for ( let i = 0; i < matches.length; i ++ ) { const match = matches[ i ]; const prop = match[ 0 ], isGlobal = this.isMethod ? ! this.getInputByName( prop ) : true; let reference = prop; if ( this.keywords[ prop ] || ( this.useKeywords && isGlobal && NodeLib.containsKeyword( prop ) ) ) { let node = this.keywords[ prop ]; if ( ! node ) { const keyword = NodeLib.getKeywordData( prop ); if ( keyword.cache ) node = builder.keywords[ prop ]; node = node || NodeLib.getKeyword( prop, builder ); if ( keyword.cache ) builder.keywords[ prop ] = node; } reference = node.build( builder ); } if ( prop !== reference ) { src = src.substring( 0, match.index + offset ) + reference + src.substring( match.index + prop.length + offset ); offset += reference.length - prop.length; } if ( this.getIncludeByName( reference ) === undefined && NodeLib.contains( reference ) ) { builder.include( NodeLib.get( reference ) ); } } if ( output === 'source' ) { return src; } else if ( this.isMethod ) { if ( ! this.isInterface ) { builder.include( this, false, src ); } return this.name; } else { return builder.format( '( ' + src + ' )', this.getType( builder ), output ); } } parse( src, includes, extensions, keywords ) { this.src = src || ''; this.includes = includes || []; this.extensions = extensions || {}; this.keywords = keywords || {}; if ( this.isMethod ) { const match = this.src.match( declarationRegexp ); this.inputs = []; if ( match && match.length == 4 ) { this.type = match[ 1 ]; this.name = match[ 2 ]; const inputs = match[ 3 ].match( propertiesRegexp ); if ( inputs ) { let i = 0; while ( i < inputs.length ) { let qualifier = inputs[ i ++ ]; let type; if ( qualifier === 'in' || qualifier === 'out' || qualifier === 'inout' ) { type = inputs[ i ++ ]; } else { type = qualifier; qualifier = ''; } const name = inputs[ i ++ ]; this.inputs.push( { name: name, type: type, qualifier: qualifier } ); } } this.isInterface = this.src.indexOf( '{' ) === - 1; } else { this.type = ''; this.name = ''; } } } copy( source ) { super.copy( source ); this.isMethod = source.isMethod; this.useKeywords = source.useKeywords; this.parse( source.src, source.includes, source.extensions, source.keywords ); if ( source.type !== undefined ) this.type = source.type; return this; } toJSON( meta ) { let data = this.getJSONNode( meta ); if ( ! data ) { data = this.createJSONNode( meta ); data.src = this.src; data.isMethod = this.isMethod; data.useKeywords = this.useKeywords; if ( ! this.isMethod ) data.type = this.type; data.extensions = JSON.parse( JSON.stringify( this.extensions ) ); data.keywords = {}; for ( const keyword in this.keywords ) { data.keywords[ keyword ] = this.keywords[ keyword ].toJSON( meta ).uuid; } if ( this.includes.length ) { data.includes = []; for ( let i = 0; i < this.includes.length; i ++ ) { data.includes.push( this.includes[ i ].toJSON( meta ).uuid ); } } } return data; } } FunctionNode.prototype.nodeType = 'Function'; FunctionNode.prototype.useKeywords = true; export { FunctionNode };