Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
JS Prototypes WIP
  • Loading branch information
RyanCavanaugh committed Dec 4, 2015
commit fabc43d0d401795531f7597eae70d209d0bb0e33
33 changes: 11 additions & 22 deletions src/compiler/binder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1367,42 +1367,31 @@ namespace ts {
}

function bindThisPropertyAssignment(node: BinaryExpression) {
// Declare a 'member' in case it turns out the container was an ES5 class
if (container.kind === SyntaxKind.FunctionExpression || container.kind === SyntaxKind.FunctionDeclaration) {
container.symbol.members = container.symbol.members || {};
declareClassMember(node, SymbolFlags.Property, SymbolFlags.PropertyExcludes);
declareSymbol(container.symbol.members, container.symbol, node, SymbolFlags.Property, SymbolFlags.PropertyExcludes);
}
}

function bindPrototypePropertyAssignment(node: BinaryExpression) {
// We saw a node of the form 'x.prototype.y = z'.
// This does two things: turns 'x' into a constructor function, and
// adds a member 'y' to the result of that constructor function
// Get 'x', the class
const classId = <Identifier>(<PropertyAccessExpression>(<PropertyAccessExpression>node.left).expression).expression;
// We saw a node of the form 'x.prototype.y = z'. Declare a 'member' y on x if x was a function.

// Look up the function in the local scope, since prototype assignments should immediately
// Look up the function in the local scope, since prototype assignments should
// follow the function declaration
const classId = <Identifier>(<PropertyAccessExpression>(<PropertyAccessExpression>node.left).expression).expression;
const funcSymbol = container.locals[classId.text];
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't guarantee that the prototype assignment immediately follows. Also, what if classId denotes a non-function, such as a variable or an interface declaration? I'm thinking you should instead check that the prototype assignment is immediately contained in a statement list and that the immediately preceding statement is a function declaration.

if (!funcSymbol) {
if (!funcSymbol || !(funcSymbol.flags & SymbolFlags.Function)) {
return;
}

// The function is now a constructor rather than a normal function
if (!funcSymbol.inferredConstructor) {
// Have the binder set up all the related class symbols for us
declareSymbol(container.locals, funcSymbol, funcSymbol.valueDeclaration, SymbolFlags.Class, SymbolFlags.None);
// funcSymbol.members = funcSymbol.members || {};
funcSymbol.members["__constructor"] = funcSymbol;
funcSymbol.inferredConstructor = true;
// Set up the members collection if it doesn't exist already
if (!funcSymbol.members) {
funcSymbol.members = {};
}

// Get the exports of the class so we can add the method to it
const funcExports = declareSymbol(funcSymbol.exports, funcSymbol, <PropertyAccessExpression>(<PropertyAccessExpression>node.left).expression, SymbolFlags.ObjectLiteral | SymbolFlags.Property, SymbolFlags.None);

// Declare the method
declareSymbol(funcExports.members, funcExports, <PropertyAccessExpression>node.left, SymbolFlags.Method, SymbolFlags.None);
// and on the members of the function so it appears in 'prototype'
declareSymbol(funcSymbol.members, funcSymbol, <PropertyAccessExpression>node.left, SymbolFlags.Method, SymbolFlags.PropertyExcludes);
// Declare the method/property
declareSymbol(funcSymbol.members, funcSymbol, <PropertyAccessExpression>node.left, SymbolFlags.Property, SymbolFlags.PropertyExcludes);
}

function bindCallExpression(node: CallExpression) {
Expand Down
1 change: 0 additions & 1 deletion src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1985,7 +1985,6 @@ namespace ts {
/* @internal */ parent?: Symbol; // Parent symbol
/* @internal */ exportSymbol?: Symbol; // Exported symbol associated with this symbol
/* @internal */ constEnumOnlyModule?: boolean; // True if module contains only const enums or other modules with only const enums
/* @internal */ inferredConstructor?: boolean; // A function promoted to constructor as the result of a prototype property assignment
}

/* @internal */
Expand Down