2015-02-03 00:30:33 +01:00
//// [parserRealSource7.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 Continuation {
public exceptionBlock = - 1 ;
constructor ( public normalBlock : number ) { }
}
function getBaseTypeLinks ( bases : ASTList , baseTypeLinks : TypeLink [ ] ) {
if ( bases ) {
var len = bases . members . length ;
if ( baseTypeLinks == null ) {
baseTypeLinks = new TypeLink [ ] ;
}
for ( var i = 0 ; i < len ; i ++ ) {
var baseExpr = bases . members [ i ] ;
var name = baseExpr ;
var typeLink = new TypeLink ( ) ;
typeLink . ast = name ;
baseTypeLinks [ baseTypeLinks . length ] = typeLink ;
}
}
return baseTypeLinks ;
}
function getBases ( type : Type , typeDecl : TypeDeclaration ) {
type . extendsTypeLinks = getBaseTypeLinks ( typeDecl . extendsList , type . extendsTypeLinks ) ;
type . implementsTypeLinks = getBaseTypeLinks ( typeDecl . implementsList , type . implementsTypeLinks ) ;
}
function addPrototypeField ( classType : Type , ast : AST , context : TypeCollectionContext ) {
var field = new ValueLocation ( ) ;
field . typeLink = new TypeLink ( ) ;
field . typeLink . ast = ast ;
field . typeLink . type = classType . instanceType ;
var fieldSymbol =
new FieldSymbol ( "prototype" , ast . minChar ,
context . checker . locationInfo . unitIndex , true , field ) ;
fieldSymbol . flags |= ( SymbolFlags . Property | SymbolFlags . BuiltIn ) ;
field . symbol = fieldSymbol ;
fieldSymbol . declAST = ast ;
classType . members . addPublicMember ( "prototype" , fieldSymbol ) ;
}
export function createNewConstructGroupForType ( type : Type ) {
var signature = new Signature ( ) ;
signature . returnType = new TypeLink ( ) ;
signature . returnType . type = type . instanceType ;
signature . parameters = [ ] ;
type . construct = new SignatureGroup ( ) ;
type . construct . addSignature ( signature ) ;
}
export function cloneParentConstructGroupForChildType ( child : Type , parent : Type ) {
child . construct = new SignatureGroup ( ) ;
var sig : Signature = null ;
if ( ! parent . construct ) {
createNewConstructGroupForType ( parent ) ;
}
for ( var i = 0 ; i < parent . construct . signatures . length ; i ++ ) {
sig = new Signature ( ) ;
sig . parameters = parent . construct . signatures [ i ] . parameters ;
sig . nonOptionalParameterCount = parent . construct . signatures [ i ] . nonOptionalParameterCount ;
sig . typeCheckStatus = parent . construct . signatures [ i ] . typeCheckStatus ;
sig . declAST = parent . construct . signatures [ i ] . declAST ;
sig . returnType = new TypeLink ( ) ;
sig . returnType . type = child . instanceType ;
child . construct . addSignature ( sig ) ;
}
}
export var globalId = "__GLO" ;
export interface IAliasScopeContext {
topLevelScope : ScopeChain ;
members : IHashTable ;
tcContext : TypeCollectionContext ;
}
function findTypeSymbolInScopeChain ( name : string , scopeChain : ScopeChain ) : Symbol {
var symbol = scopeChain . scope . find ( name , false , true ) ;
if ( symbol == null && scopeChain . previous ) {
symbol = findTypeSymbolInScopeChain ( name , scopeChain . previous ) ;
}
return symbol ;
}
function findSymbolFromAlias ( alias : AST , context : IAliasScopeContext ) : Symbol {
var symbol : Symbol = null ;
switch ( alias . nodeType ) {
case NodeType . Name :
var name = ( < Identifier > alias ) . text ;
var isDynamic = isQuoted ( name ) ;
var findSym = ( id : string ) = > {
if ( context . members ) {
return context . members . lookup ( name ) ;
}
else {
return findTypeSymbolInScopeChain ( name , context . topLevelScope ) ;
}
}
if ( isDynamic ) {
symbol = context . tcContext . checker . findSymbolForDynamicModule ( name , context . tcContext . script . locationInfo . filename , findSym ) ;
}
else {
symbol = findSym ( name ) ;
}
break ;
case NodeType . Dot :
var dottedExpr = < BinaryExpression > alias ;
var op1Sym = findSymbolFromAlias ( dottedExpr . operand1 , context ) ;
if ( op1Sym && op1Sym . getType ( ) ) {
symbol = findSymbolFromAlias ( dottedExpr . operand2 , context ) ;
}
break ;
default :
break ;
}
if ( symbol ) {
var symType = symbol . getType ( ) ;
if ( symType ) {
var members = symType . members ;
if ( members ) {
context . members = members . publicMembers ;
}
}
}
return symbol ;
}
export function preCollectImportTypes ( ast : AST , parent : AST , context : TypeCollectionContext ) {
var scopeChain = context . scopeChain ;
var typeSymbol : TypeSymbol = null ;
var modType : ModuleType = null ;
var importDecl = < ImportDeclaration > ast ;
var isExported = hasFlag ( importDecl . varFlags , VarFlags . Exported ) ;
// REVIEW: technically, this call isn't strictly necessary, since we'll find the type during the call to resolveTypeMembers
var aliasedModSymbol = findSymbolFromAlias ( importDecl . alias , { topLevelScope : scopeChain , members : null , tcContext : context } ) ;
var isGlobal = context . scopeChain . container == context . checker . gloMod ;
if ( aliasedModSymbol ) {
var aliasedModType = aliasedModSymbol . getType ( ) ;
if ( aliasedModType ) {
modType = < ModuleType > aliasedModType ;
}
}
typeSymbol = new TypeSymbol ( importDecl . id . text , importDecl . minChar ,
context . checker . locationInfo . unitIndex , modType ) ;
typeSymbol . aliasLink = importDecl ;
if ( context . scopeChain . module Decl ) {
typeSymbol . declModule = context . scopeChain . module Decl ;
}
typeSymbol . declAST = importDecl ;
importDecl . id . sym = typeSymbol ;
scopeChain . scope . enter ( scopeChain . container , ast , typeSymbol ,
context . checker . errorReporter , isExported || isGlobal , true , false ) ;
scopeChain . scope . enter ( scopeChain . container , ast , typeSymbol ,
context . checker . errorReporter , isExported || isGlobal , false , false ) ;
return true ;
}
export function preCollectModuleTypes ( ast : AST , parent : AST , context : TypeCollectionContext ) {
var scopeChain = context . scopeChain ;
var module Decl : ModuleDeclaration = < ModuleDeclaration > ast ;
var isAmbient = hasFlag ( module Decl.modFlags , ModuleFlags . Ambient ) ;
var isEnum = hasFlag ( module Decl.modFlags , ModuleFlags . IsEnum ) ;
var isGlobal = context . scopeChain . container == context . checker . gloMod ;
var isExported = hasFlag ( module Decl.modFlags , ModuleFlags . Exported ) ;
var modName = ( < Identifier > module Decl.name ) . text ;
var isDynamic = isQuoted ( modName ) ;
var symbol = scopeChain . scope . findLocal ( modName , false , false ) ;
var typeSymbol : TypeSymbol = null ;
var modType : ModuleType = null ;
if ( ( symbol == null ) || ( symbol . kind ( ) != SymbolKind . Type ) ) {
if ( modType == null ) {
var enclosedTypes = new ScopedMembers ( new DualStringHashTable ( new StringHashTable ( ) , new StringHashTable ( ) ) ) ;
var ambientEnclosedTypes = new ScopedMembers ( new DualStringHashTable ( new StringHashTable ( ) , new StringHashTable ( ) ) ) ;
modType = new ModuleType ( enclosedTypes , ambientEnclosedTypes ) ;
if ( isEnum ) {
modType . typeFlags |= TypeFlags . IsEnum ;
}
modType . members = new ScopedMembers ( new DualStringHashTable ( new StringHashTable ( ) , new StringHashTable ( ) ) ) ;
modType . ambientMembers = new ScopedMembers ( new DualStringHashTable ( new StringHashTable ( ) , new StringHashTable ( ) ) ) ;
modType . setHasImplementation ( ) ;
}
typeSymbol = new TypeSymbol ( modName , module Decl.minChar ,
context . checker . locationInfo . unitIndex , modType ) ;
if ( context . scopeChain . module Decl ) {
typeSymbol . declModule = context . scopeChain . module Decl ;
}
typeSymbol . declAST = module Decl ;
typeSymbol . prettyName = module Decl.prettyName ;
scopeChain . scope . enter ( scopeChain . container , ast , typeSymbol ,
context . checker . errorReporter , isExported || isGlobal , true , isAmbient ) ;
scopeChain . scope . enter ( scopeChain . container , ast , typeSymbol ,
context . checker . errorReporter , isExported || isGlobal , false , isAmbient ) ;
modType . symbol = typeSymbol ;
}
else {
if ( symbol && symbol . declAST && symbol . declAST . nodeType != NodeType . ModuleDeclaration ) {
context . checker . errorReporter . simpleError ( module Decl , "Conflicting symbol name for module '" + modName + "'" ) ;
}
typeSymbol = < TypeSymbol > symbol ;
// initialize new private scope for the type
var publicEnclosedTypes = typeSymbol . type . getAllEnclosedTypes ( ) . publicMembers ;
var publicEnclosedTypesTable = ( publicEnclosedTypes == null ) ? new StringHashTable ( ) : publicEnclosedTypes ;
var enclosedTypes = new ScopedMembers ( new DualStringHashTable ( publicEnclosedTypesTable , new StringHashTable ( ) ) ) ;
var publicEnclosedAmbientTypes = typeSymbol . type . getAllAmbientEnclosedTypes ( ) . publicMembers ;
var publicAmbientEnclosedTypesTable = ( publicEnclosedAmbientTypes == null ) ? new StringHashTable ( ) : publicEnclosedAmbientTypes ;
var ambientEnclosedTypes = new ScopedMembers ( new DualStringHashTable ( publicAmbientEnclosedTypesTable , new StringHashTable ( ) ) ) ;
var publicMembers = typeSymbol . type . members . publicMembers ;
var publicMembersTable = ( publicMembers == null ) ? new StringHashTable ( ) : publicMembers ;
var members = new ScopedMembers ( new DualStringHashTable ( publicMembersTable , new StringHashTable ( ) ) ) ;
var publicAmbientMembers = typeSymbol . type . ambientMembers . publicMembers ;
var publicAmbientMembersTable = ( publicAmbientMembers == null ) ? new StringHashTable ( ) : publicAmbientMembers ;
var ambientMembers = new ScopedMembers ( new DualStringHashTable ( publicAmbientMembersTable , new StringHashTable ( ) ) ) ;
modType = new ModuleType ( enclosedTypes , ambientEnclosedTypes ) ;
if ( isEnum ) {
modType . typeFlags |= TypeFlags . IsEnum ;
}
modType . members = members ;
modType . ambientMembers = ambientMembers ;
modType . setHasImplementation ( ) ;
modType . symbol = typeSymbol ;
typeSymbol . addLocation ( module Decl.minChar ) ;
typeSymbol . expansions . push ( modType ) ;
}
if ( context . scopeChain . module Decl ) {
context . scopeChain . module Decl.recordNonInterface ( ) ;
}
// REVIEW: If multiple disparate module decls for the same module don't agree
// in export privileges, how should we handle it?
if ( isExported ) {
typeSymbol . flags |= SymbolFlags . Exported ;
}
if ( ( context . scopeChain . module Decl ) ||
( context . scopeChain . container == context . checker . gloMod ) ) {
typeSymbol . flags |= SymbolFlags . ModuleMember ;
}
module Decl.mod = modType ;
pushTypeCollectionScope ( typeSymbol , modType . members ,
modType . ambientMembers ,
modType . enclosedTypes ,
modType . ambientEnclosedTypes ,
context , null , null , module Decl ) ;
return true ;
}
export function preCollectClassTypes ( ast : AST , parent : AST , context : TypeCollectionContext ) {
var scopeChain = context . scopeChain ;
var classDecl = < ClassDeclaration > ast ;
var classType : Type ;
var instanceType : Type ;
var typeSymbol : TypeSymbol = null ;
var className = ( < Identifier > classDecl . name ) . text ;
var alreadyInScope = false ;
var isAmbient = hasFlag ( classDecl . varFlags , VarFlags . Ambient ) ;
var isExported = hasFlag ( classDecl . varFlags , VarFlags . Exported ) ;
var isGlobal = context . scopeChain . container == context . checker . gloMod ;
var containerMod = < TypeSymbol > scopeChain . container ;
var foundValSymbol = false ;
typeSymbol = < TypeSymbol > scopeChain . scope . findLocal ( className , false , true ) ;
// check the value space, since an override may have been declared with the type's name
// REVIEW-CLASSES
if ( ! typeSymbol ) {
var valTypeSymbol = scopeChain . scope . findLocal ( className , false , false ) ;
if ( valTypeSymbol &&
valTypeSymbol . isType ( ) &&
valTypeSymbol . declAST &&
valTypeSymbol . declAST . nodeType == NodeType . FuncDecl &&
( < FuncDecl > valTypeSymbol . declAST ) . isSignature ( ) ) {
typeSymbol = < TypeSymbol > valTypeSymbol ;
foundValSymbol = true ;
if ( isExported ) {
typeSymbol . flags |= SymbolFlags . Exported ;
}
if ( isAmbient ) {
typeSymbol . flags |= SymbolFlags . Ambient ;
}
// the class was never entered into type space, so add it
context . scopeChain . scope . enter ( context . scopeChain . container , ast , typeSymbol ,
context . checker . errorReporter , isExported || isGlobal , true , isAmbient ) ;
}
}
if ( typeSymbol && ! foundValSymbol && ( typeSymbol . declAST != classDecl ) ) {
typeSymbol = null ;
}
if ( typeSymbol == null ) {
var valueSymbol = scopeChain . scope . findLocal ( className , false , false ) ;
classType = new Type ( ) ;
classType . setHasImplementation ( ) ;
instanceType = new Type ( ) ;
instanceType . setHasImplementation ( ) ;
classType . instanceType = instanceType ;
classType . members = new ScopedMembers ( new DualStringHashTable ( new StringHashTable ( ) , new StringHashTable ( ) ) ) ;
classType . ambientMembers = new ScopedMembers ( new DualStringHashTable ( new StringHashTable ( ) , new StringHashTable ( ) ) ) ;
addPrototypeField ( classType , classDecl , context ) ;
instanceType . members = new ScopedMembers ( new DualStringHashTable ( new StringHashTable ( ) , new StringHashTable ( ) ) ) ;
instanceType . ambientMembers = new ScopedMembers ( new DualStringHashTable ( new StringHashTable ( ) , new StringHashTable ( ) ) ) ;
typeSymbol = new TypeSymbol ( className , classDecl . minChar ,
context . checker . locationInfo . unitIndex , classType ) ;
typeSymbol . declAST = classDecl ;
typeSymbol . instanceType = instanceType ;
classType . symbol = typeSymbol ;
instanceType . symbol = typeSymbol ;
if ( context . scopeChain . module Decl ) {
context . scopeChain . module Decl.recordNonInterface ( ) ;
typeSymbol . declModule = context . scopeChain . module Decl ;
typeSymbol . flags |= SymbolFlags . ModuleMember ;
}
if ( isExported ) {
typeSymbol . flags |= SymbolFlags . Exported ;
}
if ( isAmbient ) {
typeSymbol . flags |= SymbolFlags . Ambient ;
}
ast . type = classType ;
// class in both name spaces (type for instance type; constructor representative in value space)
context . scopeChain . scope . enter ( context . scopeChain . container , ast , typeSymbol ,
context . checker . errorReporter , isExported || isGlobal , true , isAmbient ) ;
if ( valueSymbol == null ) {
context . scopeChain . scope . enter ( context . scopeChain . container , ast , typeSymbol ,
context . checker . errorReporter , isExported || isGlobal , false , isAmbient ) ;
}
}
else {
classType = typeSymbol . type ;
// If the instance type is null, a call overload was likely declared before the class constructor
if ( classType . instanceType == null ) {
classType . instanceType = new Type ( ) ;
classType . instanceType . setHasImplementation ( ) ;
classType . instanceType . members = new ScopedMembers ( new DualStringHashTable ( new StringHashTable ( ) , new StringHashTable ( ) ) ) ;
classType . instanceType . symbol = classType . symbol ;
classType . members = new ScopedMembers ( new DualStringHashTable ( new StringHashTable ( ) , new StringHashTable ( ) ) ) ;
classType . ambientMembers = new ScopedMembers ( new DualStringHashTable ( new StringHashTable ( ) , new StringHashTable ( ) ) ) ;
}
instanceType = classType . instanceType ;
ast . type = classType ;
}
// if the class has no declared constructor, either create a default signature or adapt
// it's base class's signature group
if ( ! classDecl . constructorDecl ) {
if ( typeSymbol && typeSymbol . declAST && typeSymbol . declAST . type && typeSymbol . declAST . type . call && ! ( < FuncDecl > typeSymbol . declAST ) . isOverload ) {
context . checker . errorReporter . duplicateIdentifier ( typeSymbol . declAST , typeSymbol . name ) ;
}
createNewConstructGroupForType ( classDecl . type ) ;
}
classType . typeFlags |= TypeFlags . IsClass ;
instanceType . typeFlags |= TypeFlags . IsClass ;
getBases ( instanceType , classDecl ) ;
pushTypeCollectionScope ( typeSymbol , instanceType . members , instanceType . ambientMembers , null , null ,
context , instanceType , classType , null ) ;
return true ;
}
export function preCollectInterfaceTypes ( ast : AST , parent : AST , context : TypeCollectionContext ) {
var scopeChain = context . scopeChain ;
var interfaceDecl = < InterfaceDeclaration > ast ;
var interfaceSymbol : TypeSymbol = null ;
var interfaceType : Type = null ;
var isExported = hasFlag ( interfaceDecl . varFlags , VarFlags . Exported ) ;
var isGlobal = context . scopeChain . container == context . checker . gloMod ;
var alreadyInScope = true ;
alreadyInScope = false ;
var interfaceName = ( < Identifier > interfaceDecl . name ) . text ;
interfaceSymbol = < TypeSymbol > scopeChain . scope . findLocal ( interfaceName , false , true ) ;
if ( interfaceSymbol == null ) {
interfaceType = new Type ( ) ;
interfaceSymbol = new TypeSymbol ( interfaceName ,
ast . minChar ,
context . checker . locationInfo . unitIndex ,
interfaceType ) ;
interfaceType . symbol = interfaceSymbol ;
// REVIEW: Shouldn't allocate another table for interface privates
interfaceType . members = new ScopedMembers ( new DualStringHashTable ( new StringHashTable ( ) , new StringHashTable ( ) ) ) ;
interfaceType . ambientMembers = new ScopedMembers ( new DualStringHashTable ( new StringHashTable ( ) , new StringHashTable ( ) ) ) ;
interfaceSymbol . declAST = interfaceDecl ;
interfaceSymbol . declModule = context . scopeChain . module Decl ;
}
else {
alreadyInScope = true ;
interfaceType = interfaceSymbol . type ;
}
if ( ! interfaceType ) {
interfaceType = context . checker . anyType ;
}
ast . type = interfaceType ;
getBases ( interfaceType , interfaceDecl ) ;
if ( isExported ) {
interfaceSymbol . flags |= SymbolFlags . Exported ;
}
if ( context . scopeChain . module Decl ) {
interfaceSymbol . flags |= SymbolFlags . ModuleMember ;
}
if ( ! alreadyInScope ) {
context . scopeChain . scope . enter ( context . scopeChain . container , ast ,
interfaceSymbol , context . checker . errorReporter , isGlobal || isExported , true , false ) ; // REVIEW: Technically, interfaces should be ambient
}
pushTypeCollectionScope ( interfaceSymbol , interfaceType . members , interfaceType . ambientMembers , null , null ,
context , interfaceType , null , null ) ;
return true ;
}
export function preCollectArgDeclTypes ( ast : AST , parent : AST , context : TypeCollectionContext ) {
var scopeChain = context . scopeChain ;
var argDecl = < ArgDecl > ast ;
if ( hasFlag ( argDecl . varFlags , VarFlags . Public | VarFlags . Private ) ) {
var field = new ValueLocation ( ) ;
var isPrivate = hasFlag ( argDecl . varFlags , VarFlags . Private ) ;
var fieldSymbol =
new FieldSymbol ( argDecl . id . text , argDecl . minChar ,
context . checker . locationInfo . unitIndex ,
! hasFlag ( argDecl . varFlags , VarFlags . Readonly ) ,
field ) ;
fieldSymbol . transferVarFlags ( argDecl . varFlags ) ;
field . symbol = fieldSymbol ;
fieldSymbol . declAST = ast ;
argDecl . parameterPropertySym = fieldSymbol ;
context . scopeChain . scope . enter ( context . scopeChain . container , ast ,
fieldSymbol , context . checker . errorReporter , ! isPrivate , false , false ) ;
field . typeLink = getTypeLink ( argDecl . typeExpr , context . checker , argDecl . init == null ) ;
argDecl . sym = fieldSymbol ;
}
return false ;
}
export function preCollectVarDeclTypes ( ast : AST , parent : AST , context : TypeCollectionContext ) {
var scopeChain = context . scopeChain ;
var varDecl = < VarDecl > ast ;
var isAmbient = hasFlag ( varDecl . varFlags , VarFlags . Ambient ) ;
var isExported = hasFlag ( varDecl . varFlags , VarFlags . Exported ) ;
var isGlobal = context . scopeChain . container == context . checker . gloMod ;
var isProperty = hasFlag ( varDecl . varFlags , VarFlags . Property ) ;
var isStatic = hasFlag ( varDecl . varFlags , VarFlags . Static ) ;
var isPrivate = hasFlag ( varDecl . varFlags , VarFlags . Private ) ;
var isOptional = hasFlag ( varDecl . id . flags , ASTFlags . OptionalName ) ;
if ( context . scopeChain . module Decl ) {
context . scopeChain . module Decl.recordNonInterface ( ) ;
}
if ( isProperty ||
isExported ||
( context . scopeChain . container == context . checker . gloMod ) ||
context . scopeChain . module Decl ) {
if ( isAmbient ) {
var existingSym =
< FieldSymbol > scopeChain . scope . findLocal ( varDecl . id . text , false , false ) ;
if ( existingSym ) {
varDecl . sym = existingSym ;
return false ;
}
}
// Defensive error detection...
if ( varDecl . id == null ) {
context . checker . errorReporter . simpleError ( varDecl , "Expected variable identifier at this location" ) ;
return false ;
}
var field = new ValueLocation ( ) ;
var fieldSymbol =
new FieldSymbol ( varDecl . id . text , varDecl . minChar ,
context . checker . locationInfo . unitIndex ,
( varDecl . varFlags & VarFlags . Readonly ) == VarFlags . None ,
field ) ;
fieldSymbol . transferVarFlags ( varDecl . varFlags ) ;
if ( isOptional ) {
fieldSymbol . flags |= SymbolFlags . Optional ;
}
field . symbol = fieldSymbol ;
fieldSymbol . declAST = ast ;
if ( ( context . scopeChain . module Decl ) ||
( context . scopeChain . container == context . checker . gloMod ) ) {
fieldSymbol . flags |= SymbolFlags . ModuleMember ;
fieldSymbol . declModule = context . scopeChain . module Decl ;
}
// if it's static, enter it into the class's member list directly
if ( hasFlag ( varDecl . varFlags , VarFlags . Property ) && isStatic && context . scopeChain . classType ) {
if ( ! context . scopeChain . classType . members . publicMembers . add ( varDecl . id . text , fieldSymbol ) ) {
context . checker . errorReporter . duplicateIdentifier ( ast , fieldSymbol . name ) ;
}
fieldSymbol . container = context . scopeChain . classType . symbol ;
}
else {
context . scopeChain . scope . enter ( context . scopeChain . container ,
ast ,
fieldSymbol ,
context . checker . errorReporter ,
! isPrivate && ( isProperty || isExported || isGlobal || isStatic ) ,
false ,
isAmbient ) ;
}
if ( hasFlag ( varDecl . varFlags , VarFlags . Exported ) ) {
fieldSymbol . flags |= SymbolFlags . Exported ;
}
field . typeLink = getTypeLink ( varDecl . typeExpr , context . checker ,
varDecl . init == null ) ;
varDecl . sym = fieldSymbol ;
}
return false ;
}
export function preCollectFuncDeclTypes ( ast : AST , parent : AST , context : TypeCollectionContext ) {
var scopeChain = context . scopeChain ;
// REVIEW: This will have to change when we move to "export"
if ( context . scopeChain . module Decl ) {
context . scopeChain . module Decl.recordNonInterface ( ) ;
}
var funcDecl = < FuncDecl > ast ;
var fgSym : TypeSymbol = null ;
var nameText = funcDecl . getNameText ( ) ;
var isExported = hasFlag ( funcDecl . fncFlags , FncFlags . Exported | FncFlags . ClassPropertyMethodExported ) ;
var isStatic = hasFlag ( funcDecl . fncFlags , FncFlags . Static ) ;
var isPrivate = hasFlag ( funcDecl . fncFlags , FncFlags . Private ) ;
var isConstructor = funcDecl . isConstructMember ( ) || funcDecl . isConstructor ;
var containerSym :TypeSymbol = < TypeSymbol > ( ( ( funcDecl . isMethod ( ) && isStatic ) || funcDecl . isAccessor ( ) ) && context . scopeChain . classType ? context.scopeChain.classType.symbol : context.scopeChain.container ) ;
var containerScope : SymbolScope = context . scopeChain . scope ;
var isGlobal = containerSym == context . checker . gloMod ;
var isOptional = funcDecl . name && hasFlag ( funcDecl . name . flags , ASTFlags . OptionalName ) ;
var go = false ;
var foundSymbol = false ;
// If this is a class constructor, the "container" is actually the class declaration
if ( isConstructor && hasFlag ( funcDecl . fncFlags , FncFlags . ClassMethod ) ) {
containerSym = < TypeSymbol > containerSym . container ;
containerScope = scopeChain . previous . scope ;
}
funcDecl . unitIndex = context . checker . locationInfo . unitIndex ;
// If the parent is the constructor, and this isn't an instance method, skip it.
// That way, we'll set the type during scope assignment, and can be sure that the
// function will be placed in the constructor-local scope
if ( ! funcDecl . isConstructor &&
containerSym &&
containerSym . declAST &&
containerSym . declAST . nodeType == NodeType . FuncDecl &&
( < FuncDecl > containerSym . declAST ) . isConstructor &&
! funcDecl . isMethod ( ) ) {
return go ;
}
// Interfaces and overloads
if ( hasFlag ( funcDecl . fncFlags , FncFlags . Signature ) ) {
var instType = context . scopeChain . thisType ;
// If the function is static, search in the class type's
if ( nameText && nameText != "__missing" ) {
if ( isStatic ) {
fgSym = containerSym . type . members . allMembers . lookup ( nameText ) ;
}
else {
// REVIEW: This logic should be symmetric with preCollectClassTypes
fgSym = < TypeSymbol > containerScope . findLocal ( nameText , false , false ) ;
// If we could not find the function symbol in the value context, look
// in the type context.
// This would be the case, for example, if a class constructor override
// were declared before a call override for a given class
if ( fgSym == null ) {
fgSym = < TypeSymbol > containerScope . findLocal ( nameText , false , true ) ;
}
}
if ( fgSym ) {
foundSymbol = true ;
// We'll combine ambient and non-ambient funcdecls during typecheck (for contextual typing).,
// So, if they don't agree, don't use the symbol we've found
if ( ! funcDecl . isSignature ( ) && ( hasFlag ( funcDecl . fncFlags , FncFlags . Ambient ) != hasFlag ( fgSym . flags , SymbolFlags . Ambient ) ) ) {
fgSym = null ;
}
}
}
// a function with this symbol has not yet been declared in this scope
// REVIEW: In the code below, we need to ensure that only function overloads are considered
// (E.g., if a vardecl has the same id as a function or class, we may use the vardecl symbol
// as the overload.) Defensively, however, the vardecl won't have a type yet, so it should
// suffice to just check for a null type when considering the overload symbol in
// createFunctionSignature
if ( fgSym == null ) {
if ( ! ( funcDecl . isSpecialFn ( ) ) ) {
fgSym = context . checker . createFunctionSignature ( funcDecl , containerSym , containerScope , null , ! foundSymbol ) . declAST . type . symbol ;
}
else {
fgSym = context . checker . createFunctionSignature ( funcDecl , containerSym , containerScope , containerSym , false ) . declAST . type . symbol ;
}
// set the symbol's declAST, which will point back to the first declaration (symbol or otherwise)
// related to this symbol
if ( fgSym . declAST == null || ! funcDecl . isSpecialFn ( ) ) {
fgSym . declAST = ast ;
}
}
else { // there exists a symbol with this name
if ( ( fgSym . kind ( ) == SymbolKind . Type ) ) {
fgSym = context . checker . createFunctionSignature ( funcDecl , containerSym , containerScope , fgSym , false ) . declAST . type . symbol ;
}
else {
context . checker . errorReporter . simpleError ( funcDecl , "Function or method '" + funcDecl . name . actualText + "' already declared as a property" ) ;
}
}
if ( funcDecl . isSpecialFn ( ) && ! isStatic ) {
funcDecl . type = instType ? instType : fgSym.type ;
}
else {
funcDecl . type = fgSym . type ;
}
}
else {
// declarations
if ( nameText ) {
if ( isStatic ) {
fgSym = containerSym . type . members . allMembers . lookup ( nameText ) ;
}
else {
// in the constructor case, we want to check the parent scope for overloads
if ( funcDecl . isConstructor && context . scopeChain . previous ) {
fgSym = < TypeSymbol > context . scopeChain . previous . scope . findLocal ( nameText , false , false ) ;
}
if ( fgSym == null ) {
fgSym = < TypeSymbol > containerScope . findLocal ( nameText , false , false ) ;
}
}
if ( fgSym ) {
foundSymbol = true ;
if ( ! isConstructor && fgSym . declAST . nodeType == NodeType . FuncDecl && ! ( < FuncDecl > fgSym . declAST ) . isAccessor ( ) && ! ( < FuncDecl > fgSym . declAST ) . isSignature ( ) ) {
fgSym = null ;
foundSymbol = false ;
}
}
}
// REVIEW: Move this check into the typecheck phase? It's only being run over properties...
if ( fgSym &&
! fgSym . isAccessor ( ) &&
fgSym . type &&
fgSym . type . construct &&
fgSym . type . construct . signatures != [ ] &&
( fgSym . type . construct . signatures [ 0 ] . declAST == null ||
! hasFlag ( fgSym . type . construct . signatures [ 0 ] . declAST . fncFlags , FncFlags . Ambient ) ) &&
! funcDecl . isConstructor ) {
context . checker . errorReporter . simpleError ( funcDecl , "Functions may not have class overloads" ) ;
}
if ( fgSym && ! ( fgSym . kind ( ) == SymbolKind . Type ) && funcDecl . isMethod ( ) && ! funcDecl . isAccessor ( ) && ! funcDecl . isConstructor ) {
context . checker . errorReporter . simpleError ( funcDecl , "Function or method '" + funcDecl . name . actualText + "' already declared as a property" ) ;
fgSym . type = context . checker . anyType ;
}
var sig = context . checker . createFunctionSignature ( funcDecl , containerSym , containerScope , fgSym , ! foundSymbol ) ;
// it's a getter or setter function
if ( ( ( ! fgSym || fgSym . declAST . nodeType != NodeType . FuncDecl ) && funcDecl . isAccessor ( ) ) || ( fgSym && fgSym . isAccessor ( ) ) ) {
funcDecl . accessorSymbol = context . checker . createAccessorSymbol ( funcDecl , fgSym , containerSym . type , ( funcDecl . isMethod ( ) && isStatic ) , true , containerScope , containerSym ) ;
}
funcDecl . type . symbol . declAST = ast ;
if ( funcDecl . isConstructor ) { // REVIEW: Remove when classes completely replace oldclass
go = true ;
} ;
}
if ( isExported ) {
if ( funcDecl . type . call ) {
funcDecl . type . symbol . flags |= SymbolFlags . Exported ;
}
// Accessors are set to 'exported' above
if ( fgSym && ! fgSym . isAccessor ( ) && fgSym . kind ( ) == SymbolKind . Type && fgSym . type . call ) {
fgSym . flags |= SymbolFlags . Exported ;
}
}
if ( context . scopeChain . module Decl && ! funcDecl . isSpecialFn ( ) ) {
funcDecl . type . symbol . flags |= SymbolFlags . ModuleMember ;
funcDecl . type . symbol . declModule = context . scopeChain . module Decl ;
}
if ( fgSym && isOptional ) {
fgSym . flags |= SymbolFlags . Optional ;
}
return go ;
}
export function preCollectTypes ( ast : AST , parent : AST , walker : IAstWalker ) {
var context : TypeCollectionContext = walker . state ;
var go = false ;
var scopeChain = context . scopeChain ;
if ( ast . nodeType == NodeType . Script ) {
var script : Script = < Script > ast ;
context . script = script ;
go = true ;
}
else if ( ast . nodeType == NodeType . List ) {
go = true ;
}
else if ( ast . nodeType == NodeType . ImportDeclaration ) {
go = preCollectImportTypes ( ast , parent , context ) ;
}
else if ( ast . nodeType == NodeType . With ) {
go = false ;
}
else if ( ast . nodeType == NodeType . ModuleDeclaration ) {
go = preCollectModuleTypes ( ast , parent , context ) ;
}
else if ( ast . nodeType == NodeType . ClassDeclaration ) {
go = preCollectClassTypes ( ast , parent , context ) ;
}
else if ( ast . nodeType == NodeType . Block ) {
go = true ;
}
else if ( ast . nodeType == NodeType . InterfaceDeclaration ) {
go = preCollectInterfaceTypes ( ast , parent , context ) ;
}
// This will be a constructor arg because this pass only traverses
// constructor arg lists
else if ( ast . nodeType == NodeType . ArgDecl ) {
go = preCollectArgDeclTypes ( ast , parent , context ) ;
}
else if ( ast . nodeType == NodeType . VarDecl ) {
go = preCollectVarDeclTypes ( ast , parent , context ) ;
}
else if ( ast . nodeType == NodeType . FuncDecl ) {
go = preCollectFuncDeclTypes ( ast , parent , context ) ;
}
else {
if ( ast . isStatementOrExpression ( ) && context . scopeChain . module Decl ) {
context . scopeChain . module Decl.recordNonInterface ( ) ;
}
}
walker . options . goChildren = go ;
return ast ;
}
export function postCollectTypes ( ast : AST , parent : AST , walker : IAstWalker ) {
var context : TypeCollectionContext = walker . state ;
if ( ast . nodeType == NodeType . ModuleDeclaration ) {
popTypeCollectionScope ( context ) ;
}
else if ( ast . nodeType == NodeType . ClassDeclaration ) {
popTypeCollectionScope ( context ) ;
}
else if ( ast . nodeType == NodeType . InterfaceDeclaration ) {
popTypeCollectionScope ( context ) ;
}
return ast ;
}
}
//// [parserRealSource7.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 Continuation = ( function ( ) {
function Continuation ( normalBlock ) {
this . normalBlock = normalBlock ;
this . exceptionBlock = - 1 ;
}
return Continuation ;
} ) ( ) ;
TypeScript . Continuation = Continuation ;
function getBaseTypeLinks ( bases , baseTypeLinks ) {
if ( bases ) {
var len = bases . members . length ;
if ( baseTypeLinks == null ) {
baseTypeLinks = new TypeLink [ ] ;
}
for ( var i = 0 ; i < len ; i ++ ) {
var baseExpr = bases . members [ i ] ;
var name = baseExpr ;
var typeLink = new TypeLink ( ) ;
typeLink . ast = name ;
baseTypeLinks [ baseTypeLinks . length ] = typeLink ;
}
}
return baseTypeLinks ;
}
function getBases ( type , typeDecl ) {
type . extendsTypeLinks = getBaseTypeLinks ( typeDecl . extendsList , type . extendsTypeLinks ) ;
type . implementsTypeLinks = getBaseTypeLinks ( typeDecl . implementsList , type . implementsTypeLinks ) ;
}
function addPrototypeField ( classType , ast , context ) {
var field = new ValueLocation ( ) ;
field . typeLink = new TypeLink ( ) ;
field . typeLink . ast = ast ;
field . typeLink . type = classType . instanceType ;
var fieldSymbol = new FieldSymbol ( "prototype" , ast . minChar , context . checker . locationInfo . unitIndex , true , field ) ;
fieldSymbol . flags |= ( SymbolFlags . Property | SymbolFlags . BuiltIn ) ;
field . symbol = fieldSymbol ;
fieldSymbol . declAST = ast ;
classType . members . addPublicMember ( "prototype" , fieldSymbol ) ;
}
function createNewConstructGroupForType ( type ) {
var signature = new Signature ( ) ;
signature . returnType = new TypeLink ( ) ;
signature . returnType . type = type . instanceType ;
signature . parameters = [ ] ;
type . construct = new SignatureGroup ( ) ;
type . construct . addSignature ( signature ) ;
}
TypeScript . createNewConstructGroupForType = createNewConstructGroupForType ;
function cloneParentConstructGroupForChildType ( child , parent ) {
child . construct = new SignatureGroup ( ) ;
var sig = null ;
if ( ! parent . construct ) {
createNewConstructGroupForType ( parent ) ;
}
for ( var i = 0 ; i < parent . construct . signatures . length ; i ++ ) {
sig = new Signature ( ) ;
sig . parameters = parent . construct . signatures [ i ] . parameters ;
sig . nonOptionalParameterCount = parent . construct . signatures [ i ] . nonOptionalParameterCount ;
sig . typeCheckStatus = parent . construct . signatures [ i ] . typeCheckStatus ;
sig . declAST = parent . construct . signatures [ i ] . declAST ;
sig . returnType = new TypeLink ( ) ;
sig . returnType . type = child . instanceType ;
child . construct . addSignature ( sig ) ;
}
}
TypeScript . cloneParentConstructGroupForChildType = cloneParentConstructGroupForChildType ;
TypeScript . globalId = "__GLO" ;
function findTypeSymbolInScopeChain ( name , scopeChain ) {
var symbol = scopeChain . scope . find ( name , false , true ) ;
if ( symbol == null && scopeChain . previous ) {
symbol = findTypeSymbolInScopeChain ( name , scopeChain . previous ) ;
}
return symbol ;
}
function findSymbolFromAlias ( alias , context ) {
var symbol = null ;
switch ( alias . nodeType ) {
case NodeType . Name :
var name = alias . text ;
var isDynamic = isQuoted ( name ) ;
var findSym = function ( id ) {
if ( context . members ) {
return context . members . lookup ( name ) ;
}
else {
return findTypeSymbolInScopeChain ( name , context . topLevelScope ) ;
}
} ;
if ( isDynamic ) {
symbol = context . tcContext . checker . findSymbolForDynamicModule ( name , context . tcContext . script . locationInfo . filename , findSym ) ;
}
else {
symbol = findSym ( name ) ;
}
break ;
case NodeType . Dot :
var dottedExpr = alias ;
var op1Sym = findSymbolFromAlias ( dottedExpr . operand1 , context ) ;
if ( op1Sym && op1Sym . getType ( ) ) {
symbol = findSymbolFromAlias ( dottedExpr . operand2 , context ) ;
}
break ;
default :
break ;
}
if ( symbol ) {
var symType = symbol . getType ( ) ;
if ( symType ) {
var members = symType . members ;
if ( members ) {
context . members = members . publicMembers ;
}
}
}
return symbol ;
}
function preCollectImportTypes ( ast , parent , context ) {
var scopeChain = context . scopeChain ;
var typeSymbol = null ;
var modType = null ;
var importDecl = ast ;
var isExported = hasFlag ( importDecl . varFlags , VarFlags . Exported ) ;
// REVIEW: technically, this call isn't strictly necessary, since we'll find the type during the call to resolveTypeMembers
2015-03-26 21:46:35 +01:00
var aliasedModSymbol = findSymbolFromAlias ( importDecl . alias , { topLevelScope : scopeChain , members : null , tcContext : context } ) ;
2015-02-03 00:30:33 +01:00
var isGlobal = context . scopeChain . container == context . checker . gloMod ;
if ( aliasedModSymbol ) {
var aliasedModType = aliasedModSymbol . getType ( ) ;
if ( aliasedModType ) {
modType = aliasedModType ;
}
}
typeSymbol = new TypeSymbol ( importDecl . id . text , importDecl . minChar , context . checker . locationInfo . unitIndex , modType ) ;
typeSymbol . aliasLink = importDecl ;
if ( context . scopeChain . module Decl ) {
typeSymbol . declModule = context . scopeChain . module Decl ;
}
typeSymbol . declAST = importDecl ;
importDecl . id . sym = typeSymbol ;
scopeChain . scope . enter ( scopeChain . container , ast , typeSymbol , context . checker . errorReporter , isExported || isGlobal , true , false ) ;
scopeChain . scope . enter ( scopeChain . container , ast , typeSymbol , context . checker . errorReporter , isExported || isGlobal , false , false ) ;
return true ;
}
TypeScript . preCollectImportTypes = preCollectImportTypes ;
function preCollectModuleTypes ( ast , parent , context ) {
var scopeChain = context . scopeChain ;
var module Decl = ast ;
var isAmbient = hasFlag ( module Decl.modFlags , ModuleFlags . Ambient ) ;
var isEnum = hasFlag ( module Decl.modFlags , ModuleFlags . IsEnum ) ;
var isGlobal = context . scopeChain . container == context . checker . gloMod ;
var isExported = hasFlag ( module Decl.modFlags , ModuleFlags . Exported ) ;
var modName = module Decl.name.text ;
var isDynamic = isQuoted ( modName ) ;
var symbol = scopeChain . scope . findLocal ( modName , false , false ) ;
var typeSymbol = null ;
var modType = null ;
if ( ( symbol == null ) || ( symbol . kind ( ) != SymbolKind . Type ) ) {
if ( modType == null ) {
var enclosedTypes = new ScopedMembers ( new DualStringHashTable ( new StringHashTable ( ) , new StringHashTable ( ) ) ) ;
var ambientEnclosedTypes = new ScopedMembers ( new DualStringHashTable ( new StringHashTable ( ) , new StringHashTable ( ) ) ) ;
modType = new ModuleType ( enclosedTypes , ambientEnclosedTypes ) ;
if ( isEnum ) {
modType . typeFlags |= TypeFlags . IsEnum ;
}
modType . members = new ScopedMembers ( new DualStringHashTable ( new StringHashTable ( ) , new StringHashTable ( ) ) ) ;
modType . ambientMembers = new ScopedMembers ( new DualStringHashTable ( new StringHashTable ( ) , new StringHashTable ( ) ) ) ;
modType . setHasImplementation ( ) ;
}
typeSymbol = new TypeSymbol ( modName , module Decl.minChar , context . checker . locationInfo . unitIndex , modType ) ;
if ( context . scopeChain . module Decl ) {
typeSymbol . declModule = context . scopeChain . module Decl ;
}
typeSymbol . declAST = module Decl ;
typeSymbol . prettyName = module Decl.prettyName ;
scopeChain . scope . enter ( scopeChain . container , ast , typeSymbol , context . checker . errorReporter , isExported || isGlobal , true , isAmbient ) ;
scopeChain . scope . enter ( scopeChain . container , ast , typeSymbol , context . checker . errorReporter , isExported || isGlobal , false , isAmbient ) ;
modType . symbol = typeSymbol ;
}
else {
if ( symbol && symbol . declAST && symbol . declAST . nodeType != NodeType . ModuleDeclaration ) {
context . checker . errorReporter . simpleError ( module Decl , "Conflicting symbol name for module '" + modName + "'" ) ;
}
typeSymbol = symbol ;
// initialize new private scope for the type
var publicEnclosedTypes = typeSymbol . type . getAllEnclosedTypes ( ) . publicMembers ;
var publicEnclosedTypesTable = ( publicEnclosedTypes == null ) ? new StringHashTable ( ) : publicEnclosedTypes ;
var enclosedTypes = new ScopedMembers ( new DualStringHashTable ( publicEnclosedTypesTable , new StringHashTable ( ) ) ) ;
var publicEnclosedAmbientTypes = typeSymbol . type . getAllAmbientEnclosedTypes ( ) . publicMembers ;
var publicAmbientEnclosedTypesTable = ( publicEnclosedAmbientTypes == null ) ? new StringHashTable ( ) : publicEnclosedAmbientTypes ;
var ambientEnclosedTypes = new ScopedMembers ( new DualStringHashTable ( publicAmbientEnclosedTypesTable , new StringHashTable ( ) ) ) ;
var publicMembers = typeSymbol . type . members . publicMembers ;
var publicMembersTable = ( publicMembers == null ) ? new StringHashTable ( ) : publicMembers ;
var members = new ScopedMembers ( new DualStringHashTable ( publicMembersTable , new StringHashTable ( ) ) ) ;
var publicAmbientMembers = typeSymbol . type . ambientMembers . publicMembers ;
var publicAmbientMembersTable = ( publicAmbientMembers == null ) ? new StringHashTable ( ) : publicAmbientMembers ;
var ambientMembers = new ScopedMembers ( new DualStringHashTable ( publicAmbientMembersTable , new StringHashTable ( ) ) ) ;
modType = new ModuleType ( enclosedTypes , ambientEnclosedTypes ) ;
if ( isEnum ) {
modType . typeFlags |= TypeFlags . IsEnum ;
}
modType . members = members ;
modType . ambientMembers = ambientMembers ;
modType . setHasImplementation ( ) ;
modType . symbol = typeSymbol ;
typeSymbol . addLocation ( module Decl.minChar ) ;
typeSymbol . expansions . push ( modType ) ;
}
if ( context . scopeChain . module Decl ) {
context . scopeChain . module Decl.recordNonInterface ( ) ;
}
// REVIEW: If multiple disparate module decls for the same module don't agree
// in export privileges, how should we handle it?
if ( isExported ) {
typeSymbol . flags |= SymbolFlags . Exported ;
}
2015-03-26 21:46:35 +01:00
if ( ( context . scopeChain . module Decl ) ||
( context . scopeChain . container == context . checker . gloMod ) ) {
2015-02-03 00:30:33 +01:00
typeSymbol . flags |= SymbolFlags . ModuleMember ;
}
module Decl.mod = modType ;
pushTypeCollectionScope ( typeSymbol , modType . members , modType . ambientMembers , modType . enclosedTypes , modType . ambientEnclosedTypes , context , null , null , module Decl ) ;
return true ;
}
TypeScript . preCollectModuleTypes = preCollectModuleTypes ;
function preCollectClassTypes ( ast , parent , context ) {
var scopeChain = context . scopeChain ;
var classDecl = ast ;
var classType ;
var instanceType ;
var typeSymbol = null ;
var className = classDecl . name . text ;
var alreadyInScope = false ;
var isAmbient = hasFlag ( classDecl . varFlags , VarFlags . Ambient ) ;
var isExported = hasFlag ( classDecl . varFlags , VarFlags . Exported ) ;
var isGlobal = context . scopeChain . container == context . checker . gloMod ;
var containerMod = scopeChain . container ;
var foundValSymbol = false ;
typeSymbol = scopeChain . scope . findLocal ( className , false , true ) ;
// check the value space, since an override may have been declared with the type's name
// REVIEW-CLASSES
if ( ! typeSymbol ) {
var valTypeSymbol = scopeChain . scope . findLocal ( className , false , false ) ;
2015-03-26 21:46:35 +01:00
if ( valTypeSymbol &&
valTypeSymbol . isType ( ) &&
valTypeSymbol . declAST &&
valTypeSymbol . declAST . nodeType == NodeType . FuncDecl &&
valTypeSymbol . declAST . isSignature ( ) ) {
2015-02-03 00:30:33 +01:00
typeSymbol = valTypeSymbol ;
foundValSymbol = true ;
if ( isExported ) {
typeSymbol . flags |= SymbolFlags . Exported ;
}
if ( isAmbient ) {
typeSymbol . flags |= SymbolFlags . Ambient ;
}
// the class was never entered into type space, so add it
context . scopeChain . scope . enter ( context . scopeChain . container , ast , typeSymbol , context . checker . errorReporter , isExported || isGlobal , true , isAmbient ) ;
}
}
if ( typeSymbol && ! foundValSymbol && ( typeSymbol . declAST != classDecl ) ) {
typeSymbol = null ;
}
if ( typeSymbol == null ) {
var valueSymbol = scopeChain . scope . findLocal ( className , false , false ) ;
classType = new Type ( ) ;
classType . setHasImplementation ( ) ;
instanceType = new Type ( ) ;
instanceType . setHasImplementation ( ) ;
classType . instanceType = instanceType ;
classType . members = new ScopedMembers ( new DualStringHashTable ( new StringHashTable ( ) , new StringHashTable ( ) ) ) ;
classType . ambientMembers = new ScopedMembers ( new DualStringHashTable ( new StringHashTable ( ) , new StringHashTable ( ) ) ) ;
addPrototypeField ( classType , classDecl , context ) ;
instanceType . members = new ScopedMembers ( new DualStringHashTable ( new StringHashTable ( ) , new StringHashTable ( ) ) ) ;
instanceType . ambientMembers = new ScopedMembers ( new DualStringHashTable ( new StringHashTable ( ) , new StringHashTable ( ) ) ) ;
typeSymbol = new TypeSymbol ( className , classDecl . minChar , context . checker . locationInfo . unitIndex , classType ) ;
typeSymbol . declAST = classDecl ;
typeSymbol . instanceType = instanceType ;
classType . symbol = typeSymbol ;
instanceType . symbol = typeSymbol ;
if ( context . scopeChain . module Decl ) {
context . scopeChain . module Decl.recordNonInterface ( ) ;
typeSymbol . declModule = context . scopeChain . module Decl ;
typeSymbol . flags |= SymbolFlags . ModuleMember ;
}
if ( isExported ) {
typeSymbol . flags |= SymbolFlags . Exported ;
}
if ( isAmbient ) {
typeSymbol . flags |= SymbolFlags . Ambient ;
}
ast . type = classType ;
// class in both name spaces (type for instance type; constructor representative in value space)
context . scopeChain . scope . enter ( context . scopeChain . container , ast , typeSymbol , context . checker . errorReporter , isExported || isGlobal , true , isAmbient ) ;
if ( valueSymbol == null ) {
context . scopeChain . scope . enter ( context . scopeChain . container , ast , typeSymbol , context . checker . errorReporter , isExported || isGlobal , false , isAmbient ) ;
}
}
else {
classType = typeSymbol . type ;
// If the instance type is null, a call overload was likely declared before the class constructor
if ( classType . instanceType == null ) {
classType . instanceType = new Type ( ) ;
classType . instanceType . setHasImplementation ( ) ;
classType . instanceType . members = new ScopedMembers ( new DualStringHashTable ( new StringHashTable ( ) , new StringHashTable ( ) ) ) ;
classType . instanceType . symbol = classType . symbol ;
classType . members = new ScopedMembers ( new DualStringHashTable ( new StringHashTable ( ) , new StringHashTable ( ) ) ) ;
classType . ambientMembers = new ScopedMembers ( new DualStringHashTable ( new StringHashTable ( ) , new StringHashTable ( ) ) ) ;
}
instanceType = classType . instanceType ;
ast . type = classType ;
}
// if the class has no declared constructor, either create a default signature or adapt
// it's base class's signature group
if ( ! classDecl . constructorDecl ) {
if ( typeSymbol && typeSymbol . declAST && typeSymbol . declAST . type && typeSymbol . declAST . type . call && ! typeSymbol . declAST . isOverload ) {
context . checker . errorReporter . duplicateIdentifier ( typeSymbol . declAST , typeSymbol . name ) ;
}
createNewConstructGroupForType ( classDecl . type ) ;
}
classType . typeFlags |= TypeFlags . IsClass ;
instanceType . typeFlags |= TypeFlags . IsClass ;
getBases ( instanceType , classDecl ) ;
pushTypeCollectionScope ( typeSymbol , instanceType . members , instanceType . ambientMembers , null , null , context , instanceType , classType , null ) ;
return true ;
}
TypeScript . preCollectClassTypes = preCollectClassTypes ;
function preCollectInterfaceTypes ( ast , parent , context ) {
var scopeChain = context . scopeChain ;
var interfaceDecl = ast ;
var interfaceSymbol = null ;
var interfaceType = null ;
var isExported = hasFlag ( interfaceDecl . varFlags , VarFlags . Exported ) ;
var isGlobal = context . scopeChain . container == context . checker . gloMod ;
var alreadyInScope = true ;
alreadyInScope = false ;
var interfaceName = interfaceDecl . name . text ;
interfaceSymbol = scopeChain . scope . findLocal ( interfaceName , false , true ) ;
if ( interfaceSymbol == null ) {
interfaceType = new Type ( ) ;
interfaceSymbol = new TypeSymbol ( interfaceName , ast . minChar , context . checker . locationInfo . unitIndex , interfaceType ) ;
interfaceType . symbol = interfaceSymbol ;
// REVIEW: Shouldn't allocate another table for interface privates
interfaceType . members = new ScopedMembers ( new DualStringHashTable ( new StringHashTable ( ) , new StringHashTable ( ) ) ) ;
interfaceType . ambientMembers = new ScopedMembers ( new DualStringHashTable ( new StringHashTable ( ) , new StringHashTable ( ) ) ) ;
interfaceSymbol . declAST = interfaceDecl ;
interfaceSymbol . declModule = context . scopeChain . module Decl ;
}
else {
alreadyInScope = true ;
interfaceType = interfaceSymbol . type ;
}
if ( ! interfaceType ) {
interfaceType = context . checker . anyType ;
}
ast . type = interfaceType ;
getBases ( interfaceType , interfaceDecl ) ;
if ( isExported ) {
interfaceSymbol . flags |= SymbolFlags . Exported ;
}
if ( context . scopeChain . module Decl ) {
interfaceSymbol . flags |= SymbolFlags . ModuleMember ;
}
if ( ! alreadyInScope ) {
context . scopeChain . scope . enter ( context . scopeChain . container , ast , interfaceSymbol , context . checker . errorReporter , isGlobal || isExported , true , false ) ; // REVIEW: Technically, interfaces should be ambient
}
pushTypeCollectionScope ( interfaceSymbol , interfaceType . members , interfaceType . ambientMembers , null , null , context , interfaceType , null , null ) ;
return true ;
}
TypeScript . preCollectInterfaceTypes = preCollectInterfaceTypes ;
function preCollectArgDeclTypes ( ast , parent , context ) {
var scopeChain = context . scopeChain ;
var argDecl = ast ;
if ( hasFlag ( argDecl . varFlags , VarFlags . Public | VarFlags . Private ) ) {
var field = new ValueLocation ( ) ;
var isPrivate = hasFlag ( argDecl . varFlags , VarFlags . Private ) ;
var fieldSymbol = new FieldSymbol ( argDecl . id . text , argDecl . minChar , context . checker . locationInfo . unitIndex , ! hasFlag ( argDecl . varFlags , VarFlags . Readonly ) , field ) ;
fieldSymbol . transferVarFlags ( argDecl . varFlags ) ;
field . symbol = fieldSymbol ;
fieldSymbol . declAST = ast ;
argDecl . parameterPropertySym = fieldSymbol ;
context . scopeChain . scope . enter ( context . scopeChain . container , ast , fieldSymbol , context . checker . errorReporter , ! isPrivate , false , false ) ;
field . typeLink = getTypeLink ( argDecl . typeExpr , context . checker , argDecl . init == null ) ;
argDecl . sym = fieldSymbol ;
}
return false ;
}
TypeScript . preCollectArgDeclTypes = preCollectArgDeclTypes ;
function preCollectVarDeclTypes ( ast , parent , context ) {
var scopeChain = context . scopeChain ;
var varDecl = ast ;
var isAmbient = hasFlag ( varDecl . varFlags , VarFlags . Ambient ) ;
var isExported = hasFlag ( varDecl . varFlags , VarFlags . Exported ) ;
var isGlobal = context . scopeChain . container == context . checker . gloMod ;
var isProperty = hasFlag ( varDecl . varFlags , VarFlags . Property ) ;
var isStatic = hasFlag ( varDecl . varFlags , VarFlags . Static ) ;
var isPrivate = hasFlag ( varDecl . varFlags , VarFlags . Private ) ;
var isOptional = hasFlag ( varDecl . id . flags , ASTFlags . OptionalName ) ;
if ( context . scopeChain . module Decl ) {
context . scopeChain . module Decl.recordNonInterface ( ) ;
}
2015-03-26 21:46:35 +01:00
if ( isProperty ||
isExported ||
( context . scopeChain . container == context . checker . gloMod ) ||
context . scopeChain . module Decl ) {
2015-02-03 00:30:33 +01:00
if ( isAmbient ) {
var existingSym = scopeChain . scope . findLocal ( varDecl . id . text , false , false ) ;
if ( existingSym ) {
varDecl . sym = existingSym ;
return false ;
}
}
// Defensive error detection...
if ( varDecl . id == null ) {
context . checker . errorReporter . simpleError ( varDecl , "Expected variable identifier at this location" ) ;
return false ;
}
var field = new ValueLocation ( ) ;
var fieldSymbol = new FieldSymbol ( varDecl . id . text , varDecl . minChar , context . checker . locationInfo . unitIndex , ( varDecl . varFlags & VarFlags . Readonly ) == VarFlags . None , field ) ;
fieldSymbol . transferVarFlags ( varDecl . varFlags ) ;
if ( isOptional ) {
fieldSymbol . flags |= SymbolFlags . Optional ;
}
field . symbol = fieldSymbol ;
fieldSymbol . declAST = ast ;
2015-03-26 21:46:35 +01:00
if ( ( context . scopeChain . module Decl ) ||
( context . scopeChain . container == context . checker . gloMod ) ) {
2015-02-03 00:30:33 +01:00
fieldSymbol . flags |= SymbolFlags . ModuleMember ;
fieldSymbol . declModule = context . scopeChain . module Decl ;
}
// if it's static, enter it into the class's member list directly
if ( hasFlag ( varDecl . varFlags , VarFlags . Property ) && isStatic && context . scopeChain . classType ) {
if ( ! context . scopeChain . classType . members . publicMembers . add ( varDecl . id . text , fieldSymbol ) ) {
context . checker . errorReporter . duplicateIdentifier ( ast , fieldSymbol . name ) ;
}
fieldSymbol . container = context . scopeChain . classType . symbol ;
}
else {
context . scopeChain . scope . enter ( context . scopeChain . container , ast , fieldSymbol , context . checker . errorReporter , ! isPrivate && ( isProperty || isExported || isGlobal || isStatic ) , false , isAmbient ) ;
}
if ( hasFlag ( varDecl . varFlags , VarFlags . Exported ) ) {
fieldSymbol . flags |= SymbolFlags . Exported ;
}
field . typeLink = getTypeLink ( varDecl . typeExpr , context . checker , varDecl . init == null ) ;
varDecl . sym = fieldSymbol ;
}
return false ;
}
TypeScript . preCollectVarDeclTypes = preCollectVarDeclTypes ;
function preCollectFuncDeclTypes ( ast , parent , context ) {
var scopeChain = context . scopeChain ;
// REVIEW: This will have to change when we move to "export"
if ( context . scopeChain . module Decl ) {
context . scopeChain . module Decl.recordNonInterface ( ) ;
}
var funcDecl = ast ;
var fgSym = null ;
var nameText = funcDecl . getNameText ( ) ;
var isExported = hasFlag ( funcDecl . fncFlags , FncFlags . Exported | FncFlags . ClassPropertyMethodExported ) ;
var isStatic = hasFlag ( funcDecl . fncFlags , FncFlags . Static ) ;
var isPrivate = hasFlag ( funcDecl . fncFlags , FncFlags . Private ) ;
var isConstructor = funcDecl . isConstructMember ( ) || funcDecl . isConstructor ;
var containerSym = ( ( ( funcDecl . isMethod ( ) && isStatic ) || funcDecl . isAccessor ( ) ) && context . scopeChain . classType ? context.scopeChain.classType.symbol : context.scopeChain.container ) ;
var containerScope = context . scopeChain . scope ;
var isGlobal = containerSym == context . checker . gloMod ;
var isOptional = funcDecl . name && hasFlag ( funcDecl . name . flags , ASTFlags . OptionalName ) ;
var go = false ;
var foundSymbol = false ;
// If this is a class constructor, the "container" is actually the class declaration
if ( isConstructor && hasFlag ( funcDecl . fncFlags , FncFlags . ClassMethod ) ) {
containerSym = containerSym . container ;
containerScope = scopeChain . previous . scope ;
}
funcDecl . unitIndex = context . checker . locationInfo . unitIndex ;
// If the parent is the constructor, and this isn't an instance method, skip it.
// That way, we'll set the type during scope assignment, and can be sure that the
// function will be placed in the constructor-local scope
2015-03-26 21:46:35 +01:00
if ( ! funcDecl . isConstructor &&
containerSym &&
containerSym . declAST &&
containerSym . declAST . nodeType == NodeType . FuncDecl &&
containerSym . declAST . isConstructor &&
! funcDecl . isMethod ( ) ) {
2015-02-03 00:30:33 +01:00
return go ;
}
// Interfaces and overloads
if ( hasFlag ( funcDecl . fncFlags , FncFlags . Signature ) ) {
var instType = context . scopeChain . thisType ;
// If the function is static, search in the class type's
if ( nameText && nameText != "__missing" ) {
if ( isStatic ) {
fgSym = containerSym . type . members . allMembers . lookup ( nameText ) ;
}
else {
// REVIEW: This logic should be symmetric with preCollectClassTypes
fgSym = containerScope . findLocal ( nameText , false , false ) ;
// If we could not find the function symbol in the value context, look
// in the type context.
// This would be the case, for example, if a class constructor override
// were declared before a call override for a given class
if ( fgSym == null ) {
fgSym = containerScope . findLocal ( nameText , false , true ) ;
}
}
if ( fgSym ) {
foundSymbol = true ;
// We'll combine ambient and non-ambient funcdecls during typecheck (for contextual typing).,
// So, if they don't agree, don't use the symbol we've found
if ( ! funcDecl . isSignature ( ) && ( hasFlag ( funcDecl . fncFlags , FncFlags . Ambient ) != hasFlag ( fgSym . flags , SymbolFlags . Ambient ) ) ) {
fgSym = null ;
}
}
}
// a function with this symbol has not yet been declared in this scope
// REVIEW: In the code below, we need to ensure that only function overloads are considered
// (E.g., if a vardecl has the same id as a function or class, we may use the vardecl symbol
// as the overload.) Defensively, however, the vardecl won't have a type yet, so it should
// suffice to just check for a null type when considering the overload symbol in
// createFunctionSignature
if ( fgSym == null ) {
if ( ! ( funcDecl . isSpecialFn ( ) ) ) {
fgSym = context . checker . createFunctionSignature ( funcDecl , containerSym , containerScope , null , ! foundSymbol ) . declAST . type . symbol ;
}
else {
fgSym = context . checker . createFunctionSignature ( funcDecl , containerSym , containerScope , containerSym , false ) . declAST . type . symbol ;
}
// set the symbol's declAST, which will point back to the first declaration (symbol or otherwise)
// related to this symbol
if ( fgSym . declAST == null || ! funcDecl . isSpecialFn ( ) ) {
fgSym . declAST = ast ;
}
}
else {
if ( ( fgSym . kind ( ) == SymbolKind . Type ) ) {
fgSym = context . checker . createFunctionSignature ( funcDecl , containerSym , containerScope , fgSym , false ) . declAST . type . symbol ;
}
else {
context . checker . errorReporter . simpleError ( funcDecl , "Function or method '" + funcDecl . name . actualText + "' already declared as a property" ) ;
}
}
if ( funcDecl . isSpecialFn ( ) && ! isStatic ) {
funcDecl . type = instType ? instType : fgSym.type ;
}
else {
funcDecl . type = fgSym . type ;
}
}
else {
// declarations
if ( nameText ) {
if ( isStatic ) {
fgSym = containerSym . type . members . allMembers . lookup ( nameText ) ;
}
else {
// in the constructor case, we want to check the parent scope for overloads
if ( funcDecl . isConstructor && context . scopeChain . previous ) {
fgSym = context . scopeChain . previous . scope . findLocal ( nameText , false , false ) ;
}
if ( fgSym == null ) {
fgSym = containerScope . findLocal ( nameText , false , false ) ;
}
}
if ( fgSym ) {
foundSymbol = true ;
if ( ! isConstructor && fgSym . declAST . nodeType == NodeType . FuncDecl && ! fgSym . declAST . isAccessor ( ) && ! fgSym . declAST . isSignature ( ) ) {
fgSym = null ;
foundSymbol = false ;
}
}
}
// REVIEW: Move this check into the typecheck phase? It's only being run over properties...
2015-03-26 21:46:35 +01:00
if ( fgSym &&
! fgSym . isAccessor ( ) &&
fgSym . type &&
fgSym . type . construct &&
fgSym . type . construct . signatures != [ ] &&
( fgSym . type . construct . signatures [ 0 ] . declAST == null ||
! hasFlag ( fgSym . type . construct . signatures [ 0 ] . declAST . fncFlags , FncFlags . Ambient ) ) &&
! funcDecl . isConstructor ) {
2015-02-03 00:30:33 +01:00
context . checker . errorReporter . simpleError ( funcDecl , "Functions may not have class overloads" ) ;
}
if ( fgSym && ! ( fgSym . kind ( ) == SymbolKind . Type ) && funcDecl . isMethod ( ) && ! funcDecl . isAccessor ( ) && ! funcDecl . isConstructor ) {
context . checker . errorReporter . simpleError ( funcDecl , "Function or method '" + funcDecl . name . actualText + "' already declared as a property" ) ;
fgSym . type = context . checker . anyType ;
}
var sig = context . checker . createFunctionSignature ( funcDecl , containerSym , containerScope , fgSym , ! foundSymbol ) ;
// it's a getter or setter function
if ( ( ( ! fgSym || fgSym . declAST . nodeType != NodeType . FuncDecl ) && funcDecl . isAccessor ( ) ) || ( fgSym && fgSym . isAccessor ( ) ) ) {
funcDecl . accessorSymbol = context . checker . createAccessorSymbol ( funcDecl , fgSym , containerSym . type , ( funcDecl . isMethod ( ) && isStatic ) , true , containerScope , containerSym ) ;
}
funcDecl . type . symbol . declAST = ast ;
if ( funcDecl . isConstructor ) {
go = true ;
}
;
}
if ( isExported ) {
if ( funcDecl . type . call ) {
funcDecl . type . symbol . flags |= SymbolFlags . Exported ;
}
// Accessors are set to 'exported' above
if ( fgSym && ! fgSym . isAccessor ( ) && fgSym . kind ( ) == SymbolKind . Type && fgSym . type . call ) {
fgSym . flags |= SymbolFlags . Exported ;
}
}
if ( context . scopeChain . module Decl && ! funcDecl . isSpecialFn ( ) ) {
funcDecl . type . symbol . flags |= SymbolFlags . ModuleMember ;
funcDecl . type . symbol . declModule = context . scopeChain . module Decl ;
}
if ( fgSym && isOptional ) {
fgSym . flags |= SymbolFlags . Optional ;
}
return go ;
}
TypeScript . preCollectFuncDeclTypes = preCollectFuncDeclTypes ;
function preCollectTypes ( ast , parent , walker ) {
var context = walker . state ;
var go = false ;
var scopeChain = context . scopeChain ;
if ( ast . nodeType == NodeType . Script ) {
var script = ast ;
context . script = script ;
go = true ;
}
else if ( ast . nodeType == NodeType . List ) {
go = true ;
}
else if ( ast . nodeType == NodeType . ImportDeclaration ) {
go = preCollectImportTypes ( ast , parent , context ) ;
}
else if ( ast . nodeType == NodeType . With ) {
go = false ;
}
else if ( ast . nodeType == NodeType . ModuleDeclaration ) {
go = preCollectModuleTypes ( ast , parent , context ) ;
}
else if ( ast . nodeType == NodeType . ClassDeclaration ) {
go = preCollectClassTypes ( ast , parent , context ) ;
}
else if ( ast . nodeType == NodeType . Block ) {
go = true ;
}
else if ( ast . nodeType == NodeType . InterfaceDeclaration ) {
go = preCollectInterfaceTypes ( ast , parent , context ) ;
}
else if ( ast . nodeType == NodeType . ArgDecl ) {
go = preCollectArgDeclTypes ( ast , parent , context ) ;
}
else if ( ast . nodeType == NodeType . VarDecl ) {
go = preCollectVarDeclTypes ( ast , parent , context ) ;
}
else if ( ast . nodeType == NodeType . FuncDecl ) {
go = preCollectFuncDeclTypes ( ast , parent , context ) ;
}
else {
if ( ast . isStatementOrExpression ( ) && context . scopeChain . module Decl ) {
context . scopeChain . module Decl.recordNonInterface ( ) ;
}
}
walker . options . goChildren = go ;
return ast ;
}
TypeScript . preCollectTypes = preCollectTypes ;
function postCollectTypes ( ast , parent , walker ) {
var context = walker . state ;
if ( ast . nodeType == NodeType . ModuleDeclaration ) {
popTypeCollectionScope ( context ) ;
}
else if ( ast . nodeType == NodeType . ClassDeclaration ) {
popTypeCollectionScope ( context ) ;
}
else if ( ast . nodeType == NodeType . InterfaceDeclaration ) {
popTypeCollectionScope ( context ) ;
}
return ast ;
}
TypeScript . postCollectTypes = postCollectTypes ;
} ) ( TypeScript || ( TypeScript = { } ) ) ;