Skip to content

Commit

Permalink
Add private named instance field transformation (#31)
Browse files Browse the repository at this point in the history
Implements private instance fields on top of the class properties refactor.
Signed-off-by: Joseph Watts <jwatts43@bloomberg.net>
Signed-off-by: Max Heiber <max.heiber@gmail.com>
  • Loading branch information
joeywatts authored and Joey Watts committed Jun 24, 2019
1 parent afa2ac6 commit a9cb10e
Show file tree
Hide file tree
Showing 57 changed files with 1,739 additions and 112 deletions.
4 changes: 4 additions & 0 deletions src/compiler/binder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3878,6 +3878,10 @@ namespace ts {
case SyntaxKind.BreakStatement:
transformFlags |= TransformFlags.ContainsHoistedDeclarationOrCompletion;
break;

case SyntaxKind.PrivateName:
transformFlags |= TransformFlags.ContainsClassFields;
break;
}

node.transformFlags = transformFlags | TransformFlags.HasComputedFlags;
Expand Down
455 changes: 431 additions & 24 deletions src/compiler/transformers/classFields.ts

Large diffs are not rendered by default.

22 changes: 0 additions & 22 deletions src/compiler/transformers/generators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -667,28 +667,6 @@ namespace ts {
}
}

function isCompoundAssignment(kind: BinaryOperator): kind is CompoundAssignmentOperator {
return kind >= SyntaxKind.FirstCompoundAssignment
&& kind <= SyntaxKind.LastCompoundAssignment;
}

function getOperatorForCompoundAssignment(kind: CompoundAssignmentOperator): BitwiseOperatorOrHigher {
switch (kind) {
case SyntaxKind.PlusEqualsToken: return SyntaxKind.PlusToken;
case SyntaxKind.MinusEqualsToken: return SyntaxKind.MinusToken;
case SyntaxKind.AsteriskEqualsToken: return SyntaxKind.AsteriskToken;
case SyntaxKind.AsteriskAsteriskEqualsToken: return SyntaxKind.AsteriskAsteriskToken;
case SyntaxKind.SlashEqualsToken: return SyntaxKind.SlashToken;
case SyntaxKind.PercentEqualsToken: return SyntaxKind.PercentToken;
case SyntaxKind.LessThanLessThanEqualsToken: return SyntaxKind.LessThanLessThanToken;
case SyntaxKind.GreaterThanGreaterThanEqualsToken: return SyntaxKind.GreaterThanGreaterThanToken;
case SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken: return SyntaxKind.GreaterThanGreaterThanGreaterThanToken;
case SyntaxKind.AmpersandEqualsToken: return SyntaxKind.AmpersandToken;
case SyntaxKind.BarEqualsToken: return SyntaxKind.BarToken;
case SyntaxKind.CaretEqualsToken: return SyntaxKind.CaretToken;
}
}

/**
* Visits a right-associative binary expression containing `yield`.
*
Expand Down
22 changes: 22 additions & 0 deletions src/compiler/transformers/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,28 @@ namespace ts {
isWellKnownSymbolSyntactically(expression);
}

export function isCompoundAssignment(kind: BinaryOperator): kind is CompoundAssignmentOperator {
return kind >= SyntaxKind.FirstCompoundAssignment
&& kind <= SyntaxKind.LastCompoundAssignment;
}

export function getOperatorForCompoundAssignment(kind: CompoundAssignmentOperator): BitwiseOperatorOrHigher {
switch (kind) {
case SyntaxKind.PlusEqualsToken: return SyntaxKind.PlusToken;
case SyntaxKind.MinusEqualsToken: return SyntaxKind.MinusToken;
case SyntaxKind.AsteriskEqualsToken: return SyntaxKind.AsteriskToken;
case SyntaxKind.AsteriskAsteriskEqualsToken: return SyntaxKind.AsteriskAsteriskToken;
case SyntaxKind.SlashEqualsToken: return SyntaxKind.SlashToken;
case SyntaxKind.PercentEqualsToken: return SyntaxKind.PercentToken;
case SyntaxKind.LessThanLessThanEqualsToken: return SyntaxKind.LessThanLessThanToken;
case SyntaxKind.GreaterThanGreaterThanEqualsToken: return SyntaxKind.GreaterThanGreaterThanToken;
case SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken: return SyntaxKind.GreaterThanGreaterThanGreaterThanToken;
case SyntaxKind.AmpersandEqualsToken: return SyntaxKind.AmpersandToken;
case SyntaxKind.BarEqualsToken: return SyntaxKind.BarToken;
case SyntaxKind.CaretEqualsToken: return SyntaxKind.CaretToken;
}
}

/**
* Adds super call and preceding prologue directives into the list of statements.
*
Expand Down
10 changes: 10 additions & 0 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -953,6 +953,11 @@ namespace ts {
initializer?: Expression; // Optional initializer
}

/*@internal*/
export interface PrivateNamedPropertyDeclaration extends PropertyDeclaration {
name: PrivateName;
}

export interface ObjectLiteralElement extends NamedDeclaration {
_objectLiteralBrand: any;
name?: PropertyName;
Expand Down Expand Up @@ -1777,6 +1782,11 @@ namespace ts {
name: Identifier | PrivateName;
}

/*@internal*/
export interface PrivateNamedPropertyAccessExpression extends PropertyAccessExpression {
name: PrivateName;
}

export interface SuperPropertyAccessExpression extends PropertyAccessExpression {
expression: SuperExpression;
}
Expand Down
10 changes: 10 additions & 0 deletions src/compiler/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6294,6 +6294,16 @@ namespace ts {
|| kind === SyntaxKind.ArrayBindingPattern;
}

/*@internal*/
export function isPrivateNamedPropertyDeclaration(node: Node): node is PrivateNamedPropertyDeclaration {
return isPropertyDeclaration(node) && isPrivateName(node.name);
}

/*@internal*/
export function isPrivateNamedPropertyAccessExpression(node: Node): node is PrivateNamedPropertyAccessExpression {
return isPropertyAccessExpression(node) && isPrivateName(node.name);
}

// Functions

export function isFunctionLike(node: Node): node is SignatureDeclaration {
Expand Down
15 changes: 15 additions & 0 deletions tests/baselines/reference/privateNameDeclaration.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//// [privateNameDeclaration.ts]
class A {
#name: string;
}


//// [privateNameDeclaration.js]
var _name;
var A = /** @class */ (function () {
function A() {
_name.set(this, void 0);
}
return A;
}());
_name = new WeakMap();
8 changes: 8 additions & 0 deletions tests/baselines/reference/privateNameDeclaration.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
=== tests/cases/conformance/classes/members/privateNames/privateNameDeclaration.ts ===
class A {
>A : Symbol(A, Decl(privateNameDeclaration.ts, 0, 0))

#name: string;
>#name : Symbol(A.#name, Decl(privateNameDeclaration.ts, 0, 9))
}

8 changes: 8 additions & 0 deletions tests/baselines/reference/privateNameDeclaration.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
=== tests/cases/conformance/classes/members/privateNames/privateNameDeclaration.ts ===
class A {
>A : A

#name: string;
>#name : string
}

8 changes: 5 additions & 3 deletions tests/baselines/reference/privateNameDuplicateField.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ class A {


//// [privateNameDuplicateField.js]
"use strict";
// @target es6
var _foo, _foo_1;
"use strict";
var A = /** @class */ (function () {
function A() {
this.#foo = "foo";
this.#foo = "foo";
_foo_1.set(this, "foo");
_foo_1.set(this, "foo");
}
return A;
}());
_foo = new WeakMap(), _foo_1 = new WeakMap();
8 changes: 6 additions & 2 deletions tests/baselines/reference/privateNameField.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,15 @@ class A {
}

//// [privateNameField.js]
"use strict";
// @target es6
var _classPrivateFieldSet = function (receiver, privateMap, value) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to set private field on non-instance"); } privateMap.set(receiver, value); return value; };
var _name;
"use strict";
var A = /** @class */ (function () {
function A(name) {
this.#name = name;
_name.set(this, void 0);
_classPrivateFieldSet(this, _name, name);
}
return A;
}());
_name = new WeakMap();
20 changes: 20 additions & 0 deletions tests/baselines/reference/privateNameFieldAccess.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//// [privateNameFieldAccess.ts]
class A {
#myField = "hello world";
constructor() {
console.log(this.#myField);
}
}


//// [privateNameFieldAccess.js]
var _classPrivateFieldGet = function (receiver, privateMap) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } return privateMap.get(receiver); };
var _myField;
var A = /** @class */ (function () {
function A() {
_myField.set(this, "hello world");
console.log(_classPrivateFieldGet(this, _myField));
}
return A;
}());
_myField = new WeakMap();
17 changes: 17 additions & 0 deletions tests/baselines/reference/privateNameFieldAccess.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
=== tests/cases/conformance/classes/members/privateNames/privateNameFieldAccess.ts ===
class A {
>A : Symbol(A, Decl(privateNameFieldAccess.ts, 0, 0))

#myField = "hello world";
>#myField : Symbol(A.#myField, Decl(privateNameFieldAccess.ts, 0, 9))

constructor() {
console.log(this.#myField);
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>this.#myField : Symbol(A.#myField, Decl(privateNameFieldAccess.ts, 0, 9))
>this : Symbol(A, Decl(privateNameFieldAccess.ts, 0, 0))
}
}

19 changes: 19 additions & 0 deletions tests/baselines/reference/privateNameFieldAccess.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
=== tests/cases/conformance/classes/members/privateNames/privateNameFieldAccess.ts ===
class A {
>A : A

#myField = "hello world";
>#myField : string
>"hello world" : "hello world"

constructor() {
console.log(this.#myField);
>console.log(this.#myField) : void
>console.log : (message?: any, ...optionalParams: any[]) => void
>console : Console
>log : (message?: any, ...optionalParams: any[]) => void
>this.#myField : string
>this : this
}
}

78 changes: 78 additions & 0 deletions tests/baselines/reference/privateNameFieldAssignment.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
//// [privateNameFieldAssignment.ts]
class A {
#field = 0;
constructor() {
this.#field = 1;
this.#field += 2;
this.#field -= 3;
this.#field /= 4;
this.#field *= 5;
this.#field **= 6;
this.#field %= 7;
this.#field <<= 8;
this.#field >>= 9;
this.#field >>>= 10;
this.#field &= 11;
this.#field |= 12;
this.#field ^= 13;
A.getInstance().#field = 1;
A.getInstance().#field += 2;
A.getInstance().#field -= 3;
A.getInstance().#field /= 4;
A.getInstance().#field *= 5;
A.getInstance().#field **= 6;
A.getInstance().#field %= 7;
A.getInstance().#field <<= 8;
A.getInstance().#field >>= 9;
A.getInstance().#field >>>= 10;
A.getInstance().#field &= 11;
A.getInstance().#field |= 12;
A.getInstance().#field ^= 13;
}
static getInstance() {
return new A();
}
}


//// [privateNameFieldAssignment.js]
var _classPrivateFieldSet = function (receiver, privateMap, value) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to set private field on non-instance"); } privateMap.set(receiver, value); return value; };
var _classPrivateFieldGet = function (receiver, privateMap) { if (!privateMap.has(receiver)) { throw new TypeError("attempted to get private field on non-instance"); } return privateMap.get(receiver); };
var _field;
var A = /** @class */ (function () {
function A() {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
_field.set(this, 0);
_classPrivateFieldSet(this, _field, 1);
_classPrivateFieldSet(this, _field, _classPrivateFieldGet(this, _field) + 2);
_classPrivateFieldSet(this, _field, _classPrivateFieldGet(this, _field) - 3);
_classPrivateFieldSet(this, _field, _classPrivateFieldGet(this, _field) / 4);
_classPrivateFieldSet(this, _field, _classPrivateFieldGet(this, _field) * 5);
_classPrivateFieldSet(this, _field, Math.pow(_classPrivateFieldGet(this, _field), 6));
_classPrivateFieldSet(this, _field, _classPrivateFieldGet(this, _field) % 7);
_classPrivateFieldSet(this, _field, _classPrivateFieldGet(this, _field) << 8);
_classPrivateFieldSet(this, _field, _classPrivateFieldGet(this, _field) >> 9);
_classPrivateFieldSet(this, _field, _classPrivateFieldGet(this, _field) >>> 10);
_classPrivateFieldSet(this, _field, _classPrivateFieldGet(this, _field) & 11);
_classPrivateFieldSet(this, _field, _classPrivateFieldGet(this, _field) | 12);
_classPrivateFieldSet(this, _field, _classPrivateFieldGet(this, _field) ^ 13);
_classPrivateFieldSet(A.getInstance(), _field, 1);
_classPrivateFieldSet(_a = A.getInstance(), _field, _classPrivateFieldGet(_a, _field) + 2);
_classPrivateFieldSet(_b = A.getInstance(), _field, _classPrivateFieldGet(_b, _field) - 3);
_classPrivateFieldSet(_c = A.getInstance(), _field, _classPrivateFieldGet(_c, _field) / 4);
_classPrivateFieldSet(_d = A.getInstance(), _field, _classPrivateFieldGet(_d, _field) * 5);
_classPrivateFieldSet(_e = A.getInstance(), _field, Math.pow(_classPrivateFieldGet(_e, _field), 6));
_classPrivateFieldSet(_f = A.getInstance(), _field, _classPrivateFieldGet(_f, _field) % 7);
_classPrivateFieldSet(_g = A.getInstance(), _field, _classPrivateFieldGet(_g, _field) << 8);
_classPrivateFieldSet(_h = A.getInstance(), _field, _classPrivateFieldGet(_h, _field) >> 9);
_classPrivateFieldSet(_j = A.getInstance(), _field, _classPrivateFieldGet(_j, _field) >>> 10);
_classPrivateFieldSet(_k = A.getInstance(), _field, _classPrivateFieldGet(_k, _field) & 11);
_classPrivateFieldSet(_l = A.getInstance(), _field, _classPrivateFieldGet(_l, _field) | 12);
_classPrivateFieldSet(_m = A.getInstance(), _field, _classPrivateFieldGet(_m, _field) ^ 13);
}
A.getInstance = function () {
return new A();
};
return A;
}());
_field = new WeakMap();
Loading

0 comments on commit a9cb10e

Please sign in to comment.