2015-02-03 00:30:33 +01:00
//// [parserRealSource9.ts]
// Copyright (c) Microsoft. All rights reserved. Licensed under the Apache License, Version 2.0.
// See LICENSE.txt in the project root for complete license information.
///<reference path='typescript.ts' />
module TypeScript {
export class Binder {
constructor ( public checker : TypeChecker ) { }
public resolveBaseTypeLinks ( typeLinks : TypeLink [ ] , scope : SymbolScope ) {
var extendsList : Type [ ] = null ;
if ( typeLinks ) {
extendsList = new Type [ ] ;
for ( var i = 0 , len = typeLinks . length ; i < len ; i ++ ) {
var typeLink = typeLinks [ i ] ;
this . checker . resolvingBases = true ;
this . checker . resolveTypeLink ( scope , typeLink , true ) ;
this . checker . resolvingBases = false ;
if ( typeLink . type . isClass ( ) ) {
extendsList [ i ] = typeLink . type . instanceType ;
}
else {
extendsList [ i ] = typeLink . type ;
}
}
}
return extendsList ;
}
public resolveBases ( scope : SymbolScope , type : Type ) {
type . extendsList = this . resolveBaseTypeLinks ( type . extendsTypeLinks , scope ) ;
var i = 0 , len = type . extendsList . length ;
var derivedIsClass = type . isClassInstance ( ) ;
for ( ; i < len ; i ++ ) {
var baseIsClass = type . extendsList [ i ] . isClassInstance ( ) ;
if ( type . extendsList [ i ] != this . checker . anyType ) {
if ( derivedIsClass ) {
if ( ! baseIsClass ) {
this . checker . errorReporter . simpleErrorFromSym ( type . symbol ,
"A export class may only extend other classes, " + type . extendsList [ i ] . symbol . fullName ( ) + " is an interface." ) ;
}
}
else {
if ( baseIsClass ) {
this . checker . errorReporter . simpleErrorFromSym ( type . symbol ,
"An interface may only extend other interfaces, " + type . extendsList [ i ] . symbol . fullName ( ) + " is a class." ) ;
}
}
}
}
type . implementsList = this . resolveBaseTypeLinks ( type . implementsTypeLinks , scope ) ;
if ( type . implementsList ) {
for ( i = 0 , len = type . implementsList . length ; i < len ; i ++ ) {
var iface = type . implementsList [ i ] ;
if ( iface . isClassInstance ( ) ) {
if ( derivedIsClass ) {
this . checker . errorReporter . simpleErrorFromSym ( type . symbol ,
"A class may only implement an interface; " + iface . symbol . fullName ( ) + " is a class." ) ;
}
}
}
}
}
public resolveSignatureGroup ( signatureGroup : SignatureGroup , scope : SymbolScope , instanceType : Type ) {
var supplyVar = ! ( signatureGroup . hasImplementation ) ;
for ( var i = 0 , len = signatureGroup . signatures . length ; i < len ; i ++ ) {
var signature = signatureGroup . signatures [ i ] ;
if ( instanceType ) {
signature . returnType . type = instanceType ;
}
else {
this . checker . resolveTypeLink ( scope , signature . returnType , supplyVar ) ;
}
var paramLen = signature . parameters . length ;
for ( var j = 0 ; j < paramLen ; j ++ ) {
this . bindSymbol ( scope , signature . parameters [ j ] ) ;
}
if ( signature . hasVariableArgList ) {
// check that last parameter has an array type
var lastParam = < ParameterSymbol > signature . parameters [ paramLen - 1 ] ;
lastParam . argsOffset = paramLen - 1 ;
if ( ! lastParam . getType ( ) . isArray ( ) ) {
this . checker . errorReporter . simpleErrorFromSym ( lastParam ,
"... parameter must have array type" ) ;
lastParam . parameter . typeLink . type = this . checker . makeArrayType ( lastParam . parameter . typeLink . type ) ;
}
}
}
}
public bindType ( scope : SymbolScope , type : Type , instanceType : Type ) : void {
if ( instanceType ) {
this . bindType ( scope , instanceType , null ) ;
}
if ( type . hasMembers ( ) ) {
var members = type . members ;
var ambientMembers = type . ambientMembers ;
var typeMembers = type . getAllEnclosedTypes ( ) ; // REVIEW: Should only be getting exported types?
var ambientTypeMembers = type . getAllAmbientEnclosedTypes ( ) ; // REVIEW: Should only be getting exported types?
var memberScope = new SymbolTableScope ( members , ambientMembers , typeMembers , ambientTypeMembers , type . symbol ) ;
var agg = new SymbolAggregateScope ( type . symbol ) ;
var prevCurrentModDecl = this . checker . currentModDecl ;
var prevBindStatus = this . checker . inBind ;
agg . addParentScope ( memberScope ) ;
agg . addParentScope ( scope ) ;
if ( type . isModuleType ( ) ) {
this . checker . currentModDecl = < ModuleDeclaration > type . symbol . declAST ;
this . checker . inBind = true ;
}
if ( members ) {
this . bind ( agg , type . members . allMembers ) ; // REVIEW: Should only be getting exported types?
}
if ( typeMembers ) {
this . bind ( agg , typeMembers . allMembers ) ;
}
if ( ambientMembers ) {
this . bind ( agg , ambientMembers . allMembers ) ;
}
if ( ambientTypeMembers ) {
this . bind ( agg , ambientTypeMembers . allMembers ) ;
}
this . checker . currentModDecl = prevCurrentModDecl ;
this . checker . inBind = prevBindStatus ;
}
if ( type . extendsTypeLinks ) {
this . resolveBases ( scope , type ) ;
}
if ( type . construct ) {
this . resolveSignatureGroup ( type . construct , scope , instanceType ) ;
}
if ( type . call ) {
this . resolveSignatureGroup ( type . call , scope , null ) ;
}
if ( type . index ) {
this . resolveSignatureGroup ( type . index , scope , null ) ;
}
if ( type . elementType ) {
this . bindType ( scope , type . elementType , null ) ;
}
}
public bindSymbol ( scope : SymbolScope , symbol : Symbol ) {
if ( ! symbol . bound ) {
var prevLocationInfo = this . checker . locationInfo ;
if ( ( this . checker . units ) && ( symbol . unitIndex >= 0 ) && ( symbol . unitIndex < this . checker . units . length ) ) {
this . checker . locationInfo = this . checker . units [ symbol . unitIndex ] ;
}
switch ( symbol . kind ( ) ) {
case SymbolKind . Type :
if ( symbol . flags & SymbolFlags . Bound ) {
break ;
}
var typeSymbol = < TypeSymbol > symbol ;
typeSymbol . flags |= SymbolFlags . Bound ;
// Since type collection happens out of order, a dynamic module referenced by an import statement
// may not yet be in scope when the import symbol is created. In that case, we need to search
// out the module symbol now
// Note that we'll also want to do this in resolveTypeMembers, in case the symbol is set outside the
// context of a given module (E.g., an outer import statement)
if ( typeSymbol . aliasLink && ! typeSymbol . type && typeSymbol . aliasLink . alias . nodeType == NodeType . Name ) {
var modPath = ( < Identifier > typeSymbol . aliasLink . alias ) . text ;
var modSym = this . checker . findSymbolForDynamicModule ( modPath , this . checker . locationInfo . filename , ( id ) = > scope . find ( id , false , true ) ) ;
if ( modSym ) {
typeSymbol . type = modSym . getType ( ) ;
}
}
if ( typeSymbol . type && typeSymbol . type != this . checker . gloModType ) {
this . bindType ( scope , typeSymbol . type , typeSymbol . instanceType ) ;
// bind expansions on the parent type symbol
if ( typeSymbol . type . isModuleType ( ) ) {
for ( var i = 0 ; i < typeSymbol . expansions . length ; i ++ ) {
this . bindType ( scope , typeSymbol . expansions [ i ] , typeSymbol . instanceType ) ;
}
}
}
break ;
case SymbolKind . Field :
this . checker . resolveTypeLink ( scope , ( < FieldSymbol > symbol ) . field . typeLink ,
false ) ;
break ;
case SymbolKind . Parameter :
this . checker . resolveTypeLink ( scope ,
( < ParameterSymbol > symbol ) . parameter . typeLink ,
true ) ;
break ;
}
this . checker . locationInfo = prevLocationInfo ;
}
symbol . bound = true ;
}
public bind ( scope : SymbolScope , table : IHashTable ) {
table . map (
( key , sym , binder ) = > {
binder . bindSymbol ( scope , sym ) ;
} ,
this ) ;
}
}
}
//// [parserRealSource9.js]
// Copyright (c) Microsoft. All rights reserved. Licensed under the Apache License, Version 2.0.
// See LICENSE.txt in the project root for complete license information.
///<reference path='typescript.ts' />
var TypeScript ;
( function ( TypeScript ) {
var Binder = ( function ( ) {
function Binder ( checker ) {
this . checker = checker ;
}
Binder . prototype . resolveBaseTypeLinks = function ( typeLinks , scope ) {
var extendsList = null ;
if ( typeLinks ) {
extendsList = new Type [ ] ;
for ( var i = 0 , len = typeLinks . length ; i < len ; i ++ ) {
var typeLink = typeLinks [ i ] ;
this . checker . resolvingBases = true ;
this . checker . resolveTypeLink ( scope , typeLink , true ) ;
this . checker . resolvingBases = false ;
if ( typeLink . type . isClass ( ) ) {
extendsList [ i ] = typeLink . type . instanceType ;
}
else {
extendsList [ i ] = typeLink . type ;
}
}
}
return extendsList ;
} ;
Binder . prototype . resolveBases = function ( scope , type ) {
type . extendsList = this . resolveBaseTypeLinks ( type . extendsTypeLinks , scope ) ;
var i = 0 , len = type . extendsList . length ;
var derivedIsClass = type . isClassInstance ( ) ;
for ( ; i < len ; i ++ ) {
var baseIsClass = type . extendsList [ i ] . isClassInstance ( ) ;
if ( type . extendsList [ i ] != this . checker . anyType ) {
if ( derivedIsClass ) {
if ( ! baseIsClass ) {
this . checker . errorReporter . simpleErrorFromSym ( type . symbol , "A export class may only extend other classes, " + type . extendsList [ i ] . symbol . fullName ( ) + " is an interface." ) ;
}
}
else {
if ( baseIsClass ) {
this . checker . errorReporter . simpleErrorFromSym ( type . symbol , "An interface may only extend other interfaces, " + type . extendsList [ i ] . symbol . fullName ( ) + " is a class." ) ;
}
}
}
}
type . implementsList = this . resolveBaseTypeLinks ( type . implementsTypeLinks , scope ) ;
if ( type . implementsList ) {
for ( i = 0 , len = type . implementsList . length ; i < len ; i ++ ) {
var iface = type . implementsList [ i ] ;
if ( iface . isClassInstance ( ) ) {
if ( derivedIsClass ) {
this . checker . errorReporter . simpleErrorFromSym ( type . symbol , "A class may only implement an interface; " + iface . symbol . fullName ( ) + " is a class." ) ;
}
}
}
}
} ;
Binder . prototype . resolveSignatureGroup = function ( signatureGroup , scope , instanceType ) {
var supplyVar = ! ( signatureGroup . hasImplementation ) ;
for ( var i = 0 , len = signatureGroup . signatures . length ; i < len ; i ++ ) {
var signature = signatureGroup . signatures [ i ] ;
if ( instanceType ) {
signature . returnType . type = instanceType ;
}
else {
this . checker . resolveTypeLink ( scope , signature . returnType , supplyVar ) ;
}
var paramLen = signature . parameters . length ;
for ( var j = 0 ; j < paramLen ; j ++ ) {
this . bindSymbol ( scope , signature . parameters [ j ] ) ;
}
if ( signature . hasVariableArgList ) {
// check that last parameter has an array type
var lastParam = signature . parameters [ paramLen - 1 ] ;
lastParam . argsOffset = paramLen - 1 ;
if ( ! lastParam . getType ( ) . isArray ( ) ) {
this . checker . errorReporter . simpleErrorFromSym ( lastParam , "... parameter must have array type" ) ;
lastParam . parameter . typeLink . type = this . checker . makeArrayType ( lastParam . parameter . typeLink . type ) ;
}
}
}
} ;
Binder . prototype . bindType = function ( scope , type , instanceType ) {
if ( instanceType ) {
this . bindType ( scope , instanceType , null ) ;
}
if ( type . hasMembers ( ) ) {
var members = type . members ;
var ambientMembers = type . ambientMembers ;
var typeMembers = type . getAllEnclosedTypes ( ) ; // REVIEW: Should only be getting exported types?
var ambientTypeMembers = type . getAllAmbientEnclosedTypes ( ) ; // REVIEW: Should only be getting exported types?
var memberScope = new SymbolTableScope ( members , ambientMembers , typeMembers , ambientTypeMembers , type . symbol ) ;
var agg = new SymbolAggregateScope ( type . symbol ) ;
var prevCurrentModDecl = this . checker . currentModDecl ;
var prevBindStatus = this . checker . inBind ;
agg . addParentScope ( memberScope ) ;
agg . addParentScope ( scope ) ;
if ( type . isModuleType ( ) ) {
this . checker . currentModDecl = type . symbol . declAST ;
this . checker . inBind = true ;
}
if ( members ) {
this . bind ( agg , type . members . allMembers ) ; // REVIEW: Should only be getting exported types?
}
if ( typeMembers ) {
this . bind ( agg , typeMembers . allMembers ) ;
}
if ( ambientMembers ) {
this . bind ( agg , ambientMembers . allMembers ) ;
}
if ( ambientTypeMembers ) {
this . bind ( agg , ambientTypeMembers . allMembers ) ;
}
this . checker . currentModDecl = prevCurrentModDecl ;
this . checker . inBind = prevBindStatus ;
}
if ( type . extendsTypeLinks ) {
this . resolveBases ( scope , type ) ;
}
if ( type . construct ) {
this . resolveSignatureGroup ( type . construct , scope , instanceType ) ;
}
if ( type . call ) {
this . resolveSignatureGroup ( type . call , scope , null ) ;
}
if ( type . index ) {
this . resolveSignatureGroup ( type . index , scope , null ) ;
}
if ( type . elementType ) {
this . bindType ( scope , type . elementType , null ) ;
}
} ;
Binder . prototype . bindSymbol = function ( scope , symbol ) {
if ( ! symbol . bound ) {
var prevLocationInfo = this . checker . locationInfo ;
if ( ( this . checker . units ) && ( symbol . unitIndex >= 0 ) && ( symbol . unitIndex < this . checker . units . length ) ) {
this . checker . locationInfo = this . checker . units [ symbol . unitIndex ] ;
}
switch ( symbol . kind ( ) ) {
case SymbolKind . Type :
if ( symbol . flags & SymbolFlags . Bound ) {
break ;
}
var typeSymbol = symbol ;
typeSymbol . flags |= SymbolFlags . Bound ;
// Since type collection happens out of order, a dynamic module referenced by an import statement
// may not yet be in scope when the import symbol is created. In that case, we need to search
// out the module symbol now
// Note that we'll also want to do this in resolveTypeMembers, in case the symbol is set outside the
// context of a given module (E.g., an outer import statement)
if ( typeSymbol . aliasLink && ! typeSymbol . type && typeSymbol . aliasLink . alias . nodeType == NodeType . Name ) {
var modPath = typeSymbol . aliasLink . alias . text ;
2015-03-26 21:46:35 +01:00
var modSym = this . checker . findSymbolForDynamicModule ( modPath , this . checker . locationInfo . filename , function ( id ) { return scope . find ( id , false , true ) ; } ) ;
2015-02-03 00:30:33 +01:00
if ( modSym ) {
typeSymbol . type = modSym . getType ( ) ;
}
}
if ( typeSymbol . type && typeSymbol . type != this . checker . gloModType ) {
this . bindType ( scope , typeSymbol . type , typeSymbol . instanceType ) ;
// bind expansions on the parent type symbol
if ( typeSymbol . type . isModuleType ( ) ) {
for ( var i = 0 ; i < typeSymbol . expansions . length ; i ++ ) {
this . bindType ( scope , typeSymbol . expansions [ i ] , typeSymbol . instanceType ) ;
}
}
}
break ;
case SymbolKind . Field :
this . checker . resolveTypeLink ( scope , symbol . field . typeLink , false ) ;
break ;
case SymbolKind . Parameter :
this . checker . resolveTypeLink ( scope , symbol . parameter . typeLink , true ) ;
break ;
}
this . checker . locationInfo = prevLocationInfo ;
}
symbol . bound = true ;
} ;
Binder . prototype . bind = function ( scope , table ) {
table . map ( function ( key , sym , binder ) {
binder . bindSymbol ( scope , sym ) ;
} , this ) ;
} ;
return Binder ;
} ) ( ) ;
TypeScript . Binder = Binder ;
} ) ( TypeScript || ( TypeScript = { } ) ) ;