module ts { export const enum ModuleInstanceState { NonInstantiated = 0 , Instantiated = 1 , ConstEnumOnly = 2 } export function getModuleInstanceState ( node ) { if ( node . kind === SyntaxKind . InterfaceDeclaration ) { return ModuleInstanceState . NonInstantiated ; } else if ( isConstEnumDeclaration ( node ) ) { return ModuleInstanceState . ConstEnumOnly ; } else if ( node . kind === SyntaxKind . ImportDeclaration && ! ( node . flags & NodeFlags . Export ) ) { return ModuleInstanceState . NonInstantiated ; } else if ( node . kind === SyntaxKind . ModuleBlock ) { var state = ModuleInstanceState . NonInstantiated ; forEachChild ( node , n => { switch ( getModuleInstanceState ( n ) ) { case ModuleInstanceState . NonInstantiated : return false ; case ModuleInstanceState . ConstEnumOnly : state = ModuleInstanceState . ConstEnumOnly ; return false ; case ModuleInstanceState . Instantiated : state = ModuleInstanceState . Instantiated ; return true ; } } ) ; return state ; } else if ( node . kind === SyntaxKind . ModuleDeclaration ) { return getModuleInstanceState ( ( < ModuleDeclaration > node ) . body ) ; } else { return ModuleInstanceState . Instantiated ; } } /**
     * Returns false if any of the following are true:
     *   1. declaration has no name
     *   2. declaration has a literal name (not computed)
     *   3. declaration has a computed property name that is a known symbol
     */ export function hasComputedNameButNotSymbol ( declaration ) { return declaration . name && declaration . name . kind === SyntaxKind . ComputedPropertyName ; } export function bindSourceFile ( file ) { var parent ; var container ; var blockScopeContainer ; var lastContainer ; var symbolCount = 0 ; var Symbol = objectAllocator . getSymbolConstructor ( ) ; if ( ! file . locals ) { file . locals = { } ; container = blockScopeContainer = file ; bind ( file ) ; file . symbolCount = symbolCount ; } function createSymbol ( flags , name ) { symbolCount ++ ; return new Symbol ( flags , name ) ; } function addDeclarationToSymbol ( symbol , node , symbolKind ) { symbol . flags |= symbolKind ; if ( ! symbol . declarations ) symbol . declarations = [ ] ; symbol . declarations . push ( node ) ; if ( symbolKind & SymbolFlags . HasExports && ! symbol . exports ) symbol . exports = { } ; if ( symbolKind & SymbolFlags . HasMembers && ! symbol . members ) symbol . members = { } ; node . symbol = symbol ; if ( symbolKind & SymbolFlags . Value && ! symbol . valueDeclaration ) symbol . valueDeclaration = node ; } function getDeclarationName ( node ) { if ( node . name ) { if ( node . kind === SyntaxKind . ModuleDeclaration && node . name . kind === SyntaxKind . StringLiteral ) { return '"' + ( < LiteralExpression > node . name ) . text + '"' ; } Debug . assert ( ! hasComputedNameButNotSymbol ( node ) ) ; return ( < Identifier | LiteralExpression > node . name ) . text ; } switch ( node . kind ) { case SyntaxKind . ConstructorType : case SyntaxKind . Constructor : return "__constructor" ; case SyntaxKind . FunctionType : case SyntaxKind . CallSignature : return "__call" ; case SyntaxKind . ConstructSignature : return "__new" ; case SyntaxKind . IndexSignature : return "__index" ; } } function getDisplayName ( node ) { return node . name ? declarationNameToString ( node . name ) : getDeclarationName ( node ) ; } function declareSymbol ( symbols , parent , node , includes , excludes ) { if ( hasComputedNameButNotSymbol ( node ) ) { return undefined ; } var name = getDeclarationName ( node ) ; if ( name !== undefined ) { var symbol = hasProperty ( symbols , name ) ? symbols [ name ] : ( symbols [ name ] = createSymbol ( 0 , name ) ) ; if ( symbol . flags & excludes ) { if ( node . name ) { node . name . parent = node ; } var message = symbol . flags & SymbolFlags . BlockScopedVariable ? Diagnostics . Cannot_redeclare_block_scoped_variable_0 : Diagnostics . Duplicate_identifier_0 ; forEach ( symbol . declarations , declaration => { file . semanticDiagnostics . push ( createDiagnosticForNode ( declaration . name , message , getDisplayName ( declaration ) ) ) ; } ) ; file . semanticDiagnostics . push ( createDiagnosticForNode ( node . name , message , getDisplayName ( node ) ) ) ; symbol = createSymbol ( 0 , name ) ; } } else { symbol = createSymbol ( 0 , "__missing" ) ; } addDeclarationToSymbol ( symbol , node , includes ) ; symbol . parent = parent ; if ( node . kind === SyntaxKind . ClassDeclaration && symbol . exports ) { var prototypeSymbol = createSymbol ( SymbolFlags . Property | SymbolFlags . Prototype , "prototype" ) ; if ( hasProperty ( symbol . exports , prototypeSymbol . name ) ) { if ( node . name ) { node . name . parent = node ; } file . semanticDiagnostics . push ( createDiagnosticForNode ( symbol . exports [ prototypeSymbol . name ] . declarations [ 0 ] , Diagnostics . Duplicate_identifier_0 , prototypeSymbol . name ) ) ; } symbol . exports [ prototypeSymbol . name ] = prototypeSymbol ; prototypeSymbol . parent = symbol ; } return symbol ; } function isAmbientContext ( node ) { while ( node ) { if ( node . flags & NodeFlags . Ambient ) return true ; node = node . parent ; } return false ; } function declareModuleMember ( node , symbolKind , symbolExcludes ) { var exportKind = 0 ; if ( symbolKind & SymbolFlags . Value ) { exportKind |= SymbolFlags . ExportValue ; } if ( symbolKind & SymbolFlags . Type ) { exportKind |= SymbolFlags . ExportType ; } if ( symbolKind & SymbolFlags . Namespace ) { exportKind |= SymbolFlags . ExportNamespace ; } if ( node . flags & NodeFlags . Export || ( node . kind !== SyntaxKind . ImportDeclaration && isAmbientContext ( container ) ) ) { if ( exportKind ) { var local = declareSymbol ( container . locals , undefined , node , exportKind , symbolExcludes ) ; local . exportSymbol = declareSymbol ( container . symbol . exports , container . symbol , node , symbolKind , symbolExcludes ) ; node . localSymbol = local ; } else { declareSymbol ( container . symbol . exports , container . symbol , node , symbolKind , symbolExcludes ) ; } } else { declareSymbol ( container . locals , undefined , node , symbolKind , symbolExcludes ) ; } } function bindChildren ( node , symbolKind , isBlockScopeContainer ) { if ( symbolKind & SymbolFlags . HasLocals ) { node . locals = { } ; } var saveParent = parent ; var saveContainer = container ; var savedBlockScopeContainer = blockScopeContainer ; parent = node ; if ( symbolKind & SymbolFlags . IsContainer ) { container = node ; if ( lastContainer !== container && ! container . nextContainer ) { if ( lastContainer ) { lastContainer . nextContainer = container ; } lastContainer = container ; } } if ( isBlockScopeContainer ) { blockScopeContainer = node ; } forEachChild ( node , bind ) ; container = saveContainer ; parent = saveParent ; blockScopeContainer = savedBlockScopeContainer ; } function bindDeclaration ( node , symbolKind , symbolExcludes , isBlockScopeContainer ) { switch ( container . kind ) { case SyntaxKind . ModuleDeclaration : declareModuleMember ( node , symbolKind , symbolExcludes ) ; break ; case SyntaxKind . SourceFile : if ( isExternalModule ( < SourceFile > container ) ) { declareModuleMember ( node , symbolKind , symbolExcludes ) ; break ; } case SyntaxKind . FunctionType : case SyntaxKind . ConstructorType : case SyntaxKind . CallSignature : case SyntaxKind . ConstructSignature : case SyntaxKind . IndexSignature : case SyntaxKind . Method : case SyntaxKind . Constructor : case SyntaxKind . GetAccessor : case SyntaxKind . SetAccessor : case SyntaxKind . FunctionDeclaration : case SyntaxKind . FunctionExpression : case SyntaxKind . ArrowFunction : declareSymbol ( container . locals , undefined , node , symbolKind , symbolExcludes ) ; break ; case SyntaxKind . ClassDeclaration : if ( node . flags & NodeFlags . Static ) { declareSymbol ( container . symbol . exports , container . symbol , node , symbolKind , symbolExcludes ) ; break ; } case SyntaxKind . TypeLiteral : case SyntaxKind . ObjectLiteralExpression : case SyntaxKind . InterfaceDeclaration : declareSymbol ( container . symbol . members , container . symbol , node , symbolKind , symbolExcludes ) ; break ; case SyntaxKind . EnumDeclaration : declareSymbol ( container . symbol . exports , container . symbol , node , symbolKind , symbolExcludes ) ; break ; } bindChildren ( node , symbolKind , isBlockScopeContainer ) ; } function bindConstructorDeclaration ( node ) { bindDeclaration ( node , SymbolFlags . Constructor , 0 , true ) ; forEach ( node . parameters , p => { if ( p . flags & ( NodeFlags . Public | NodeFlags . Private | NodeFlags . Protected ) ) { bindDeclaration ( p , SymbolFlags . Property , SymbolFlags . PropertyExcludes , false ) ; } } ) ; } function bindModuleDeclaration ( node ) { if ( node . name . kind === SyntaxKind . StringLiteral ) { bindDeclaration ( node , SymbolFlags . ValueModule , SymbolFlags . ValueModuleExcludes , true ) ; } else { var state = getModuleInstanceState ( node ) ; if ( state === ModuleInstanceState . NonInstantiated ) { bindDeclaration ( node , SymbolFlags . NamespaceModule , SymbolFlags . NamespaceModuleExcludes , true ) ; } else { bindDeclaration ( node , SymbolFlags . ValueModule , SymbolFlags . ValueModuleExcludes , true ) ; if ( state === ModuleInstanceState . ConstEnumOnly ) { node . symbol . constEnumOnlyModule = true ; } else if ( node . symbol . constEnumOnlyModule ) { node . symbol . constEnumOnlyModule = false ; } } } } function bindFunctionOrConstructorType ( node ) { var symbolKind = node . kind === SyntaxKind . FunctionType ? SymbolFlags . CallSignature : SymbolFlags . ConstructSignature ; var symbol = createSymbol ( symbolKind , getDeclarationName ( node ) ) ; addDeclarationToSymbol ( symbol , node , symbolKind ) ; bindChildren ( node , symbolKind , false ) ; var typeLiteralSymbol = createSymbol ( SymbolFlags . TypeLiteral , "__type" ) ; addDeclarationToSymbol ( typeLiteralSymbol , node , SymbolFlags . TypeLiteral ) ; typeLiteralSymbol . members = { } ; typeLiteralSymbol . members [ node . kind === SyntaxKind . FunctionType ? "__call" : "__new" ] = symbol ; } function bindAnonymousDeclaration ( node , symbolKind , name , isBlockScopeContainer ) { var symbol = createSymbol ( symbolKind , name ) ; addDeclarationToSymbol ( symbol , node , symbolKind ) ; bindChildren ( node , symbolKind , isBlockScopeContainer ) ; } function bindCatchVariableDeclaration ( node ) { var symbol = createSymbol ( SymbolFlags . FunctionScopedVariable , node . name . text || "__missing" ) ; addDeclarationToSymbol ( symbol , node , SymbolFlags . FunctionScopedVariable ) ; var saveParent = parent ; var savedBlockScopeContainer = blockScopeContainer ; parent = blockScopeContainer = node ; forEachChild ( node , bind ) ; parent = saveParent ; blockScopeContainer = savedBlockScopeContainer ; } function bindBlockScopedVariableDeclaration ( node ) { switch ( blockScopeContainer . kind ) { case SyntaxKind . ModuleDeclaration : declareModuleMember ( node , SymbolFlags . BlockScopedVariable , SymbolFlags . BlockScopedVariableExcludes ) ; break ; case SyntaxKind . SourceFile : if ( isExternalModule ( < SourceFile > container ) ) { declareModuleMember ( node , SymbolFlags . BlockScopedVariable , SymbolFlags . BlockScopedVariableExcludes ) ; break ; } default : if ( ! blockScopeContainer . locals ) { blockScopeContainer . locals = { } ; } declareSymbol ( blockScopeContainer . locals , undefined , node , SymbolFlags . BlockScopedVariable , SymbolFlags . BlockScopedVariableExcludes ) ; } bindChildren ( node , SymbolFlags . BlockScopedVariable , false ) ; } function bind ( node ) { node . parent = parent ; switch ( node . kind ) { case SyntaxKind . TypeParameter : bindDeclaration ( < Declaration > node , SymbolFlags . TypeParameter , SymbolFlags . TypeParameterExcludes , false ) ; break ; case SyntaxKind . Parameter : bindDeclaration ( < Declaration > node , SymbolFlags . FunctionScopedVariable , SymbolFlags . ParameterExcludes , false ) ; break ; case SyntaxKind . VariableDeclaration : if ( node . flags & NodeFlags . BlockScoped ) { bindBlockScopedVariableDeclaration ( < Declaration > node ) ; } else { bindDeclaration ( < Declaration > node , SymbolFlags . FunctionScopedVariable , SymbolFlags . FunctionScopedVariableExcludes , false ) ; } break ; case SyntaxKind . Property : case SyntaxKind . PropertyAssignment : case SyntaxKind . ShorthandPropertyAssignment : bindDeclaration ( < Declaration > node , SymbolFlags . Property , SymbolFlags . PropertyExcludes , false ) ; break ; case SyntaxKind . EnumMember : bindDeclaration ( < Declaration > node , SymbolFlags . EnumMember , SymbolFlags . EnumMemberExcludes , false ) ; break ; case SyntaxKind . CallSignature : bindDeclaration ( < Declaration > node , SymbolFlags . CallSignature , 0 , false ) ; break ; case SyntaxKind . ConstructSignature : bindDeclaration ( < Declaration > node , SymbolFlags . ConstructSignature , 0 , true ) ; break ; case SyntaxKind . Method : bindDeclaration ( < Declaration > node , SymbolFlags . Method , isObjectLiteralMethod ( node ) ? SymbolFlags . PropertyExcludes : SymbolFlags . MethodExcludes , true ) ; break ; case SyntaxKind . IndexSignature : bindDeclaration ( < Declaration > node , SymbolFlags . IndexSignature , 0 , false ) ; break ; case SyntaxKind . FunctionDeclaration : bindDeclaration ( < Declaration > node , SymbolFlags . Function , SymbolFlags . FunctionExcludes , true ) ; break ; case SyntaxKind . Constructor : bindConstructorDeclaration ( < ConstructorDeclaration > node ) ; break ; case SyntaxKind . GetAccessor : bindDeclaration ( < Declaration > node , SymbolFlags . GetAccessor , SymbolFlags . GetAccessorExcludes , true ) ; break ; case SyntaxKind . SetAccessor : bindDeclaration ( < Declaration > node , SymbolFlags . SetAccessor , SymbolFlags . SetAccessorExcludes , true ) ; break ; case SyntaxKind . FunctionType : case SyntaxKind . ConstructorType : bindFunctionOrConstructorType ( < SignatureDeclaration > node ) ; break ; case SyntaxKind . TypeLiteral : bindAnonymousDeclaration ( < TypeLiteralNode > node , SymbolFlags . TypeLiteral , "__type" , false ) ; break ; case SyntaxKind . ObjectLiteralExpression : bindAnonymousDeclaration ( < ObjectLiteralExpression > node , SymbolFlags . ObjectLiteral , "__object" , false ) ; break ; case SyntaxKind . FunctionExpression : case SyntaxKind . ArrowFunction : bindAnonymousDeclaration ( < FunctionExpression > node , SymbolFlags . Function , "__function" , true ) ; break ; case SyntaxKind . CatchClause : bindCatchVariableDeclaration ( < CatchClause > node ) ; break ; case SyntaxKind . ClassDeclaration : bindDeclaration ( < Declaration > node , SymbolFlags . Class , SymbolFlags . ClassExcludes , false ) ; break ; case SyntaxKind . InterfaceDeclaration : bindDeclaration ( < Declaration > node , SymbolFlags . Interface , SymbolFlags . InterfaceExcludes , false ) ; break ; case SyntaxKind . TypeAliasDeclaration : bindDeclaration ( < Declaration > node , SymbolFlags . TypeAlias , SymbolFlags . TypeAliasExcludes , false ) ; break ; case SyntaxKind . EnumDeclaration : if ( isConst ( node ) ) { bindDeclaration ( < Declaration > node , SymbolFlags . ConstEnum , SymbolFlags . ConstEnumExcludes , false ) ; } else { bindDeclaration ( < Declaration > node , SymbolFlags . RegularEnum , SymbolFlags . RegularEnumExcludes , false ) ; } break ; case SyntaxKind . ModuleDeclaration : bindModuleDeclaration ( < ModuleDeclaration > node ) ; break ; case SyntaxKind . ImportDeclaration : bindDeclaration ( < Declaration > node , SymbolFlags . Import , SymbolFlags . ImportExcludes , false ) ; break ; case SyntaxKind . SourceFile : if ( isExternalModule ( < SourceFile > node ) ) { bindAnonymousDeclaration ( < SourceFile > node , SymbolFlags . ValueModule , '"' + removeFileExtension ( ( < SourceFile > node ) . filename ) + '"' , true ) ; break ; } case SyntaxKind . Block : case SyntaxKind . TryBlock : case SyntaxKind . CatchClause : case SyntaxKind . FinallyBlock : case SyntaxKind . ForStatement : case SyntaxKind . ForInStatement : case SyntaxKind . SwitchStatement : bindChildren ( node , 0 , true ) ; break ; default : var saveParent = parent ; parent = node ; forEachChild ( node , bind ) ; parent = saveParent ; } } } }