/**
 * Copyright (c) 2016-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */ import * as AlgebraicType from './algebraic-type' ; import * as AlgebraicTypeUtils from './algebraic-type-utils' ; import * as Maybe from './maybe' ; import * as ObjC from './objc' ; import * as ObjCRenderer from './objc-renderer' ; import * as StringUtils from './string-utils' ; function localFunctionBlockDefinitionNameForSubtype ( subtype ) { return ( 'match' + StringUtils . capitalize ( AlgebraicTypeUtils . subtypeNameFromSubtype ( subtype ) ) ) ; } function matchBlockNameForSubtype ( subtype ) { return ( StringUtils . lowercased ( AlgebraicTypeUtils . subtypeNameFromSubtype ( subtype ) ) + 'MatchHandler' ) ; } function nameOfBlockTypeParameter ( parameter ) { return parameter . name ; } function keywordForInvokingMatchMethodForSubtype ( algebraicType , subtype , index ) { if ( index === 0 ) { return AlgebraicTypeUtils . firstKeywordForMatchMethodFromSubtype ( algebraicType , null , false , subtype ) ; } else { return AlgebraicTypeUtils . keywordForMatchMethodFromSubtype ( algebraicType , null , false , subtype ) ; } } function referencedGenericTypeRefersToParentTypeName ( referencedGenericType , parentTypeName ) { return ( referencedGenericType . name == parentTypeName || referencedGenericType . referencedGenericTypes . some ( ( r ) => referencedGenericTypeRefersToParentTypeName ( r , parentTypeName ) ) ) ; } function subtypeRefersToParentTypeName ( type , parentTypeName ) { return ( type . name == parentTypeName || type . referencedGenericTypes . some ( ( r ) => referencedGenericTypeRefersToParentTypeName ( r , parentTypeName ) ) ) ; } /**
 * If an algebraic data type refers to itself, we need to forward-declare the
 * type itself so that typedefs for matcher blocks can refer to it.
 */ export function forwardDeclarationsForAlgebraicType ( algebraicType ) { for ( const subtype of algebraicType . subtypes ) { const refersToParent = subtype . match ( ( collection ) => collection . attributes . some ( ( a ) => subtypeRefersToParentTypeName ( a . type , algebraicType . name ) ) , ( a ) => subtypeRefersToParentTypeName ( a . type , algebraicType . name ) ) ; if ( refersToParent ) { return [ ObjC . ForwardDeclaration . ForwardClassDeclaration ( algebraicType . name ) , ] ; } } return [ ] ; } export function buildLocalFunctionBlockDefinitionsForSubtype ( algebraicType , subtype , blockInvocationWrapper ) { const blockType = AlgebraicTypeUtils . blockTypeForSubtype ( algebraicType , null , subtype ) ; const paramList = blockType . parameters . length > 0 ? blockType . parameters . map ( ObjCRenderer . toBlockTypeParameterString ) . join ( ', ' ) : 'void' ; const start = `${ blockType . name } __unsafe_unretained ${ localFunctionBlockDefinitionNameForSubtype ( subtype ) } = ^(${ paramList }) {` ; const blockBody = blockInvocationWrapper ( `${ matchBlockNameForSubtype ( subtype ) }(${ blockType . parameters . map ( nameOfBlockTypeParameter ) . join ( ', ' ) })` ) ; const end = [ '};' , '' ] ; const blockCode = [ start ] . concat ( StringUtils . indent ( 2 ) ( blockBody ) ) . concat ( end ) ; return blockCode ; } export function buildKeywordPartsForInvokingMatchMethodForSubtype ( algebraicType , soFar , subtype , index ) { const keyword = keywordForInvokingMatchMethodForSubtype ( algebraicType , subtype , index ) ; const code = keyword . name + ':' + localFunctionBlockDefinitionNameForSubtype ( subtype ) ; return soFar . concat ( code ) ; }