339 lines
16 KiB
TypeScript
339 lines
16 KiB
TypeScript
/// <reference path="types.ts"/>
|
|
/// <reference path="core.ts"/>
|
|
/// <reference path="scanner.ts"/>
|
|
/// <reference path="parser.ts"/>
|
|
|
|
module ts {
|
|
|
|
export function isInstantiated(node: Node): boolean {
|
|
// A module is uninstantiated if it contains only
|
|
// 1. interface declarations
|
|
if (node.kind === SyntaxKind.InterfaceDeclaration) {
|
|
return false;
|
|
}
|
|
// 2. non - exported import declarations
|
|
else if (node.kind === SyntaxKind.ImportDeclaration && !(node.flags & NodeFlags.Export)) {
|
|
return false;
|
|
}
|
|
// 3. other uninstantiated module declarations.
|
|
else if (node.kind === SyntaxKind.ModuleBlock && !forEachChild(node, isInstantiated)) {
|
|
return false;
|
|
}
|
|
else if (node.kind === SyntaxKind.ModuleDeclaration && !isInstantiated((<ModuleDeclaration>node).body)) {
|
|
return false;
|
|
}
|
|
else {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
export function bindSourceFile(file: SourceFile) {
|
|
|
|
var parent: Node;
|
|
var container: Declaration;
|
|
var symbolCount = 0;
|
|
var Symbol = objectAllocator.getSymbolConstructor();
|
|
|
|
if (!file.locals) {
|
|
file.locals = {};
|
|
container = file;
|
|
bind(file);
|
|
file.symbolCount = symbolCount;
|
|
}
|
|
|
|
function createSymbol(flags: SymbolFlags, name: string): Symbol {
|
|
symbolCount++;
|
|
return new Symbol(flags, name);
|
|
}
|
|
|
|
function addDeclarationToSymbol(symbol: Symbol, node: Declaration, symbolKind: SymbolFlags) {
|
|
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: Declaration): string {
|
|
if (node.name) {
|
|
if (node.kind === SyntaxKind.ModuleDeclaration && node.name.kind === SyntaxKind.StringLiteral) {
|
|
return '"' + node.name.text + '"';
|
|
}
|
|
return node.name.text;
|
|
}
|
|
switch (node.kind) {
|
|
case SyntaxKind.Constructor: return "__constructor";
|
|
case SyntaxKind.CallSignature: return "__call";
|
|
case SyntaxKind.ConstructSignature: return "__new";
|
|
case SyntaxKind.IndexSignature: return "__index";
|
|
}
|
|
}
|
|
|
|
function getDisplayName(node: Declaration): string {
|
|
return node.name ? identifierToString(node.name) : getDeclarationName(node);
|
|
}
|
|
|
|
function declareSymbol(symbols: SymbolTable, parent: Symbol, node: Declaration, includes: SymbolFlags, excludes: SymbolFlags): Symbol {
|
|
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;
|
|
}
|
|
file.semanticErrors.push(createDiagnosticForNode(node.name ? node.name : node,
|
|
Diagnostics.Duplicate_identifier_0, 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) {
|
|
// TypeScript 1.0 spec (April 2014): 8.4
|
|
// Every class automatically contains a static property member named 'prototype',
|
|
// the type of which is an instantiation of the class type with type Any supplied as a type argument for each type parameter.
|
|
// It is an error to explicitly declare a static property member with the name 'prototype'.
|
|
var prototypeSymbol = createSymbol(SymbolFlags.Property | SymbolFlags.Prototype, "prototype");
|
|
if (hasProperty(symbol.exports, prototypeSymbol.name)) {
|
|
if (node.name) {
|
|
node.name.parent = node;
|
|
}
|
|
file.semanticErrors.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: Node): boolean {
|
|
while (node) {
|
|
if (node.flags & NodeFlags.Ambient) return true;
|
|
node = node.parent;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function declareModuleMember(node: Declaration, symbolKind: SymbolFlags, symbolExcludes: SymbolFlags) {
|
|
// Exported module members are given 2 symbols: A local symbol that is classified with an ExportValue,
|
|
// ExportType, or ExportContainer flag, and an associated export symbol with all the correct flags set
|
|
// on it. There are 2 main reasons:
|
|
//
|
|
// 1. We treat locals and exports of the same name as mutually exclusive within a container.
|
|
// That means the binder will issue a Duplicate Identifier error if you mix locals and exports
|
|
// with the same name in the same container.
|
|
// TODO: Make this a more specific error and decouple it from the exclusion logic.
|
|
// 2. When we checkIdentifier in the checker, we set its resolved symbol to the local symbol,
|
|
// but return the export symbol (by calling getExportSymbolOfValueSymbolIfExported). That way
|
|
// when the emitter comes back to it, it knows not to qualify the name if it was found in a containing scope.
|
|
var exportKind = 0;
|
|
var exportExcludes = 0;
|
|
if (symbolKind & SymbolFlags.Value) {
|
|
exportKind |= SymbolFlags.ExportValue;
|
|
exportExcludes |= SymbolFlags.Value;
|
|
}
|
|
if (symbolKind & SymbolFlags.Type) {
|
|
exportKind |= SymbolFlags.ExportType;
|
|
exportExcludes |= SymbolFlags.Type;
|
|
}
|
|
if (symbolKind & SymbolFlags.Namespace) {
|
|
exportKind |= SymbolFlags.ExportNamespace;
|
|
exportExcludes |= SymbolFlags.Namespace;
|
|
}
|
|
if (node.flags & NodeFlags.Export || (node.kind !== SyntaxKind.ImportDeclaration && isAmbientContext(container))) {
|
|
if (exportKind) {
|
|
var local = declareSymbol(container.locals, undefined, node, exportKind, exportExcludes);
|
|
local.exportSymbol = declareSymbol(container.symbol.exports, container.symbol, node, symbolKind, symbolExcludes);
|
|
}
|
|
else {
|
|
declareSymbol(container.symbol.exports, container.symbol, node, symbolKind, symbolExcludes);
|
|
}
|
|
}
|
|
else {
|
|
declareSymbol(container.locals, undefined, node, symbolKind, symbolExcludes | exportKind);
|
|
}
|
|
}
|
|
|
|
function bindDeclaration(node: Declaration, symbolKind: SymbolFlags, symbolExcludes: SymbolFlags) {
|
|
switch (container.kind) {
|
|
case SyntaxKind.ModuleDeclaration:
|
|
declareModuleMember(node, symbolKind, symbolExcludes);
|
|
break;
|
|
case SyntaxKind.SourceFile:
|
|
if (container.flags & NodeFlags.ExternalModule) {
|
|
declareModuleMember(node, symbolKind, symbolExcludes);
|
|
break;
|
|
}
|
|
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.ObjectLiteral:
|
|
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;
|
|
}
|
|
if (symbolKind & SymbolFlags.HasLocals) node.locals = {};
|
|
var saveParent = parent;
|
|
var saveContainer = container;
|
|
parent = node;
|
|
if (symbolKind & SymbolFlags.IsContainer) container = node;
|
|
forEachChild(node, bind);
|
|
container = saveContainer;
|
|
parent = saveParent;
|
|
}
|
|
|
|
function bindConstructorDeclaration(node: ConstructorDeclaration) {
|
|
bindDeclaration(node, SymbolFlags.Constructor, 0);
|
|
forEach(node.parameters, p => {
|
|
if (p.flags & (NodeFlags.Public | NodeFlags.Private)) {
|
|
bindDeclaration(p, SymbolFlags.Property, SymbolFlags.PropertyExcludes);
|
|
}
|
|
});
|
|
}
|
|
|
|
function bindModuleDeclaration(node: ModuleDeclaration) {
|
|
if (node.name.kind === SyntaxKind.StringLiteral) {
|
|
bindDeclaration(node, SymbolFlags.ValueModule, SymbolFlags.ValueModuleExcludes);
|
|
}
|
|
else if (isInstantiated(node)) {
|
|
bindDeclaration(node, SymbolFlags.ValueModule, SymbolFlags.ValueModuleExcludes);
|
|
}
|
|
else {
|
|
bindDeclaration(node, SymbolFlags.NamespaceModule, SymbolFlags.NamespaceModuleExcludes);
|
|
}
|
|
}
|
|
|
|
function bindAnonymousDeclaration(node: Node, symbolKind: SymbolFlags, name: string) {
|
|
var symbol = createSymbol(symbolKind, name);
|
|
addDeclarationToSymbol(symbol, node, symbolKind);
|
|
if (symbolKind & SymbolFlags.HasLocals) node.locals = {};
|
|
var saveParent = parent;
|
|
var saveContainer = container;
|
|
parent = node;
|
|
container = node;
|
|
forEachChild(node, bind);
|
|
container = saveContainer;
|
|
parent = saveParent;
|
|
}
|
|
|
|
function bindCatchVariableDeclaration(node: CatchBlock) {
|
|
var symbol = createSymbol(SymbolFlags.Variable, node.variable.text || "__missing");
|
|
addDeclarationToSymbol(symbol, node.variable, SymbolFlags.Variable);
|
|
var saveParent = parent;
|
|
parent = node;
|
|
forEachChild(node, bind);
|
|
parent = saveParent;
|
|
}
|
|
|
|
function bind(node: Node) {
|
|
node.parent = parent;
|
|
switch (node.kind) {
|
|
case SyntaxKind.TypeParameter:
|
|
bindDeclaration(<Declaration>node, SymbolFlags.TypeParameter, SymbolFlags.TypeParameterExcludes);
|
|
break;
|
|
case SyntaxKind.Parameter:
|
|
bindDeclaration(<Declaration>node, SymbolFlags.Variable, SymbolFlags.ParameterExcludes);
|
|
break;
|
|
case SyntaxKind.VariableDeclaration:
|
|
bindDeclaration(<Declaration>node, SymbolFlags.Variable, SymbolFlags.VariableExcludes);
|
|
break;
|
|
case SyntaxKind.Property:
|
|
case SyntaxKind.PropertyAssignment:
|
|
bindDeclaration(<Declaration>node, SymbolFlags.Property, SymbolFlags.PropertyExcludes);
|
|
break;
|
|
case SyntaxKind.EnumMember:
|
|
bindDeclaration(<Declaration>node, SymbolFlags.EnumMember, SymbolFlags.EnumMemberExcludes);
|
|
break;
|
|
case SyntaxKind.CallSignature:
|
|
bindDeclaration(<Declaration>node, SymbolFlags.CallSignature, 0);
|
|
break;
|
|
case SyntaxKind.Method:
|
|
bindDeclaration(<Declaration>node, SymbolFlags.Method, SymbolFlags.MethodExcludes);
|
|
break;
|
|
case SyntaxKind.ConstructSignature:
|
|
bindDeclaration(<Declaration>node, SymbolFlags.ConstructSignature, 0);
|
|
break;
|
|
case SyntaxKind.IndexSignature:
|
|
bindDeclaration(<Declaration>node, SymbolFlags.IndexSignature, 0);
|
|
break;
|
|
case SyntaxKind.FunctionDeclaration:
|
|
bindDeclaration(<Declaration>node, SymbolFlags.Function, SymbolFlags.FunctionExcludes);
|
|
break;
|
|
case SyntaxKind.Constructor:
|
|
bindConstructorDeclaration(<ConstructorDeclaration>node);
|
|
break;
|
|
case SyntaxKind.GetAccessor:
|
|
bindDeclaration(<Declaration>node, SymbolFlags.GetAccessor, SymbolFlags.GetAccessorExcludes);
|
|
break;
|
|
case SyntaxKind.SetAccessor:
|
|
bindDeclaration(<Declaration>node, SymbolFlags.SetAccessor, SymbolFlags.SetAccessorExcludes);
|
|
break;
|
|
case SyntaxKind.TypeLiteral:
|
|
bindAnonymousDeclaration(node, SymbolFlags.TypeLiteral, "__type");
|
|
break;
|
|
case SyntaxKind.ObjectLiteral:
|
|
bindAnonymousDeclaration(node, SymbolFlags.ObjectLiteral, "__object");
|
|
break;
|
|
case SyntaxKind.FunctionExpression:
|
|
case SyntaxKind.ArrowFunction:
|
|
bindAnonymousDeclaration(node, SymbolFlags.Function, "__function");
|
|
break;
|
|
case SyntaxKind.CatchBlock:
|
|
bindCatchVariableDeclaration(<CatchBlock>node);
|
|
break;
|
|
case SyntaxKind.ClassDeclaration:
|
|
bindDeclaration(<Declaration>node, SymbolFlags.Class, SymbolFlags.ClassExcludes);
|
|
break;
|
|
case SyntaxKind.InterfaceDeclaration:
|
|
bindDeclaration(<Declaration>node, SymbolFlags.Interface, SymbolFlags.InterfaceExcludes);
|
|
break;
|
|
case SyntaxKind.EnumDeclaration:
|
|
bindDeclaration(<Declaration>node, SymbolFlags.Enum, SymbolFlags.EnumExcludes);
|
|
break;
|
|
case SyntaxKind.ModuleDeclaration:
|
|
bindModuleDeclaration(<ModuleDeclaration>node);
|
|
break;
|
|
case SyntaxKind.ImportDeclaration:
|
|
bindDeclaration(<Declaration>node, SymbolFlags.Import, SymbolFlags.ImportExcludes);
|
|
break;
|
|
case SyntaxKind.SourceFile:
|
|
if (node.flags & NodeFlags.ExternalModule) {
|
|
bindAnonymousDeclaration(node, SymbolFlags.ValueModule, '"' + getModuleNameFromFilename((<SourceFile>node).filename) + '"');
|
|
break;
|
|
}
|
|
default:
|
|
var saveParent = parent;
|
|
parent = node;
|
|
forEachChild(node, bind);
|
|
parent = saveParent;
|
|
}
|
|
}
|
|
}
|
|
}
|