import War3Map from '../../../parsers/w3x/map' ; import War3MapWtg from '../../../parsers/w3x/wtg/file' ; import ECA from '../../../parsers/w3x/wtg/eca' ; import SubParameters from '../../../parsers/w3x/wtg/subparameters' ; import { FunctionSignature , TriggerData } from '../../../parsers/w3x/wtg/triggerdata' ; import WeuData from './data' ; function typeFunctionCall ( wtg , object , signatures , customTriggerData ) { if ( signatures . has ( object . name ) ) { const signature = < FunctionSignature > signatures . get ( object . name ) ; const args = signature . args ; for ( const [ index , parameter ] of object . parameters . entries ( ) ) { const { type , value } = parameter ; if ( type === 1 ) { for ( const variable of wtg . variables ) { if ( variable . name === value ) { args [ index ] = variable . type ; break ; } } } else if ( type === 2 ) { if ( parameter . subParameters ) { const subParameters = parameter . subParameters ; const childSignature = customTriggerData . getFunction ( subParameters . type , subParameters . name ) ; if ( childSignature ) { const returnType = childSignature . returnType ; if ( returnType && returnType !== 'AnyType' ) { args [ index ] = returnType ; } } } } else if ( type === 3 ) { if ( value . startsWith ( 'TRIGSTER_' ) || value . includes ( '\\' ) ) { args [ index ] = 'string' ; } else if ( value === 'true' || value === 'false' ) { args [ index ] = 'boolean' ; } else if ( ! isNaN ( parseFloat ( value ) ) ) { const valueAsFloat = parseFloat ( value ) ; if ( ! isNaN ( valueAsFloat ) ) { if ( Number . isInteger ( valueAsFloat ) && ! value . includes ( '.' ) ) { args [ index ] = 'integer' ; } else { args [ index ] = 'real' ; } } } } } } for ( const parameter of object . parameters ) { if ( parameter . type === 2 && parameter . subParameters ) { typeFunctionCall ( wtg , parameter . subParameters , signatures , customTriggerData ) ; } } if ( object instanceof ECA ) { for ( const child of object . ecas ) { typeFunctionCall ( wtg , child , signatures , customTriggerData ) ; } } } const BIGGEST_SIGNATURE = 20 ; /**
 * Parses a WTG file, but with a twist - it also tries to fill in unknown function signatures.
 *
 * This lets the WEU converter to handle maps with small TriggerData modifications that are unknown.
 *
 * Unfortunately it only handles simple cases - if there is an unknown signature in an unknown signature, there is no way to parse it as far as I can tell.
 *
 * With that being said, it already managed to parse and mostly fill the signatures of relevant test maps.
 */ export default function parseWtg ( map , customTriggerData , data ) { let wtg ; const signatures = new Map ( ) ; let currentName ; let currentSignature ; let searching = true ; while ( searching ) { try { wtg = map . readTriggers ( customTriggerData ) ; searching = false ; } catch ( e ) { if ( e instanceof Error ) { const message = e . message ; if ( message . endsWith ( 'Unknown signature' ) ) { const end = message . lastIndexOf ( '"' ) ; const start = message . lastIndexOf ( '"' , end - 1 ) + 1 ; const nameAndType = message . slice ( start , end ) ; const [ name , type ] = nameAndType . split ( ':' ) ; const typeAsNumber = parseInt ( type ) ; const signature = { args : [ ] , scriptName : null , returnType : typeAsNumber === 3 ? 'AnyType' : null } ; currentName = name . toLowerCase ( ) ; currentSignature = signature ; signatures . set ( name , signature ) ; customTriggerData . externalFunctions [ typeAsNumber ] [ currentName ] = currentSignature ; } else if ( currentName && currentSignature ) { currentSignature . args . push ( 'AnyType' ) ; if ( currentSignature . args . length > BIGGEST_SIGNATURE ) { searching = false ; } } } } } if ( signatures . size ) { if ( wtg ) { for ( const trigger of wtg . triggers ) { for ( const eca of trigger . ecas ) { typeFunctionCall ( wtg , eca , signatures , customTriggerData ) ; } } } for ( const [ name , signature ] of signatures ) { data . change ( 'unknownsignature' , `Unknown signature` , `${ name }(${ signature . args . join ( ', ' ) }) => ${ signature . returnType ? signature . returnType : 'void' }` ) ; } } return wtg ; }