Skip to content

Commit 1e35593

Browse files
committed
Adds the transformFiles API
1 parent ba9181c commit 1e35593

6 files changed

Lines changed: 792 additions & 13 deletions

File tree

src/compiler/factory.ts

Lines changed: 218 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
/// <reference path="core.ts"/>
22
/// <reference path="utilities.ts"/>
33

4+
/* @internal */
45
namespace ts {
56
let NodeConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node;
67
let SourceFileConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node;
78

8-
export function createNode(kind: SyntaxKind, pos?: number, end?: number): Node {
9+
function createNode(kind: SyntaxKind, pos?: number, end?: number): Node {
910
if (kind === SyntaxKind.SourceFile) {
1011
return new (SourceFileConstructor || (SourceFileConstructor = objectAllocator.getSourceFileConstructor()))(kind, pos, end);
1112
}
@@ -14,7 +15,10 @@ namespace ts {
1415
}
1516
}
1617

17-
/* @internal */
18+
function allocateNode(kind: SyntaxKind, location?: TextRange) {
19+
return location ? createNode(kind, location.pos, location.end) : createSynthesizedNode(kind);
20+
}
21+
1822
export function createNodeArray<T extends Node>(elements?: T[], pos?: number, end?: number): NodeArray<T> {
1923
const array = <NodeArray<T>>(elements || []);
2024
array.pos = pos;
@@ -23,7 +27,6 @@ namespace ts {
2327
return array;
2428
}
2529

26-
/* @internal */
2730
export function createModifiersArray(elements?: Modifier[], pos?: number, end?: number): ModifiersArray {
2831
const array = <ModifiersArray>(elements || []);
2932
array.pos = pos;
@@ -33,19 +36,16 @@ namespace ts {
3336
return array;
3437
}
3538

36-
/* @internal */
3739
export function createSynthesizedNode(kind: SyntaxKind, startsOnNewLine?: boolean): Node {
3840
const node = <SynthesizedNode>createNode(kind, /*pos*/ -1, /*end*/ -1);
3941
node.startsOnNewLine = startsOnNewLine;
4042
return node;
4143
}
4244

43-
/* @internal */
4445
export function createSynthesizedNodeArray<T extends Node>(elements?: T[]): NodeArray<T> {
4546
return createNodeArray(elements, /*pos*/ -1, /*end*/ -1);
4647
}
4748

48-
/* @internal */
4949
export function createSynthesizedModifiersArray(elements?: Modifier[]): ModifiersArray {
5050
return createModifiersArray(elements, /*pos*/ -1, /*end*/ -1);
5151
}
@@ -61,7 +61,6 @@ namespace ts {
6161
* @param parent The parent for the new node.
6262
* @param original An optional pointer to the original source tree node.
6363
*/
64-
/* @internal */
6564
export function cloneNode<T extends Node>(node: T, location?: TextRange, flags?: NodeFlags, parent?: Node, original?: Node): T {
6665
// We don't use "clone" from core.ts here, as we need to preserve the prototype chain of
6766
// the original node. We also need to exclude specific properties and only include own-
@@ -93,46 +92,252 @@ namespace ts {
9392
return clone;
9493
}
9594

96-
/* @internal */
9795
export function createNodeArrayNode<T extends Node>(elements: T[]): NodeArrayNode<T> {
9896
const node = <NodeArrayNode<T>>createSynthesizedNode(SyntaxKind.NodeArrayNode);
9997
node.nodes = createNodeArray(elements);
10098
return node;
10199
}
102100

103-
/* @internal */
104101
export function createReturn(expression?: Expression): ReturnStatement {
105102
const node = <ReturnStatement>createSynthesizedNode(SyntaxKind.ReturnStatement);
106103
node.expression = expression;
107104
return node;
108105
}
109106

110-
/* @internal */
111107
export function createStatement(expression: Expression): ExpressionStatement {
112108
const node = <ExpressionStatement>createSynthesizedNode(SyntaxKind.ExpressionStatement);
113109
node.expression = expression;
114110
return node;
115111
}
116112

117-
/* @internal */
118113
export function createVariableStatement(declarationList: VariableDeclarationList): VariableStatement {
119114
const node = <VariableStatement>createSynthesizedNode(SyntaxKind.VariableStatement);
120115
node.declarationList = declarationList;
121116
return node;
122117
}
123118

124-
/* @internal */
125119
export function createVariableDeclarationList(declarations: VariableDeclaration[]): VariableDeclarationList {
126120
const node = <VariableDeclarationList>createSynthesizedNode(SyntaxKind.VariableDeclarationList);
127121
node.declarations = createNodeArray(declarations);
128122
return node;
129123
}
130124

131-
/* @internal */
132125
export function createBlock(statements: Statement[]): Block {
133126
const block = <Block>createSynthesizedNode(SyntaxKind.Block);
134127
block.statements = createNodeArray(statements);
135128
return block;
136129
}
137130

131+
export function createVariableDeclaration(name: BindingPattern | Identifier, initializer?: Expression, location?: TextRange): VariableDeclaration {
132+
const node = <VariableDeclaration>allocateNode(SyntaxKind.VariableDeclaration, location);
133+
node.name = name;
134+
node.initializer = initializer;
135+
return node;
136+
}
137+
138+
export function createIdentifier(text: string): Identifier {
139+
const node = <Identifier>allocateNode(SyntaxKind.Identifier);
140+
node.text = text;
141+
return node;
142+
}
143+
144+
export function createTempVariable(tempKind: TempVariableKind): Identifier {
145+
const name = <Identifier>allocateNode(SyntaxKind.Identifier);
146+
name.tempKind = tempKind;
147+
getNodeId(name);
148+
return name;
149+
}
150+
151+
export function createLiteral(value: string): StringLiteral;
152+
export function createLiteral(value: number): LiteralExpression;
153+
export function createLiteral(value: string | number | boolean | void): PrimaryExpression;
154+
export function createLiteral<T extends PrimaryExpression>(value: string | number | boolean | void): T {
155+
if (typeof value === "string") {
156+
const node = <T & StringLiteral>allocateNode(SyntaxKind.StringLiteral);
157+
node.text = value;
158+
return node;
159+
}
160+
else if (typeof value === "number") {
161+
const node = <T & LiteralExpression>allocateNode(SyntaxKind.NumericLiteral);
162+
node.text = value.toString();
163+
return node;
164+
}
165+
else if (typeof value === "boolean") {
166+
return <T>allocateNode(value ? SyntaxKind.TrueKeyword : SyntaxKind.FalseKeyword);
167+
}
168+
else if (value === null) {
169+
return <T>allocateNode(SyntaxKind.NullKeyword);
170+
}
171+
}
172+
173+
export function createVoid(expression: UnaryExpression) {
174+
const node = <VoidExpression>allocateNode(SyntaxKind.VoidExpression);
175+
node.expression = expression;
176+
return node;
177+
}
178+
179+
export function createVoidZero() {
180+
return createVoid(createLiteral(0));
181+
}
182+
183+
export function createPropertyAccess(expression: Expression, name: string | Identifier) {
184+
const node = <PropertyAccessExpression>allocateNode(SyntaxKind.PropertyAccessExpression);
185+
node.expression = parenthesizeForAccess(expression);
186+
node.dotToken = createSynthesizedNode(SyntaxKind.DotToken);
187+
node.name = coerceIdentifier(name);
188+
return node;
189+
}
190+
191+
export function createElementAccess(expression: Expression, index: string | number | Expression) {
192+
const node = <ElementAccessExpression>allocateNode(SyntaxKind.ElementAccessExpression);
193+
node.expression = parenthesizeForAccess(expression);
194+
node.argumentExpression = coerceExpression(index);
195+
return node;
196+
}
197+
198+
export function createConditional(condition: Expression, whenTrue: Expression, whenFalse: Expression) {
199+
const node = <ConditionalExpression>allocateNode(SyntaxKind.ConditionalExpression);
200+
node.condition = condition;
201+
node.questionToken = createSynthesizedNode(SyntaxKind.QualifiedName);
202+
node.whenTrue = whenTrue;
203+
node.colonToken = createSynthesizedNode(SyntaxKind.ColonToken);
204+
node.whenFalse = whenFalse;
205+
return node;
206+
}
207+
208+
export function createBinary(left: Expression, operator: SyntaxKind, right: Expression, location?: TextRange) {
209+
const node = <BinaryExpression>allocateNode(SyntaxKind.BinaryExpression, location);
210+
node.left = parenthesizeForBinary(left, operator, BinaryOperand.Left);
211+
node.operatorToken = createSynthesizedNode(operator);
212+
node.right = parenthesizeForBinary(right, operator, BinaryOperand.Right);
213+
return node;
214+
}
215+
216+
export function createAssignment(left: Expression, right: Expression, location?: TextRange) {
217+
return createBinary(left, SyntaxKind.EqualsToken, right, location);
218+
}
219+
220+
export function createStrictEquality(left: Expression, right: Expression) {
221+
return createBinary(left, SyntaxKind.EqualsEqualsEqualsToken, right);
222+
}
223+
224+
export function createComma(left: Expression, right: Expression) {
225+
return <Expression>createBinary(left, SyntaxKind.CommaToken, right);
226+
}
227+
228+
export function createCall(expression: Expression, argumentsArray: Expression[]) {
229+
const node = <CallExpression>allocateNode(SyntaxKind.CallExpression);
230+
node.expression = parenthesizeForAccess(expression);
231+
node.arguments = createNodeArray(argumentsArray);
232+
return node;
233+
}
234+
235+
export function createArraySlice(array: Expression, start?: number | Expression) {
236+
const argumentsList: Expression[] = start !== undefined ? [coerceExpression(start)] : [];
237+
return createCall(createPropertyAccess(array, "slice"), argumentsList);
238+
}
239+
240+
export function parenthesizeExpression(expression: Expression) {
241+
const node = <ParenthesizedExpression>allocateNode(SyntaxKind.ParenthesizedExpression);
242+
node.expression = expression;
243+
return node;
244+
}
245+
246+
export function inlineExpressions(expressions: Expression[]) {
247+
return reduceLeft(expressions, createComma);
248+
}
249+
250+
function coerceIdentifier(value: string | Identifier) {
251+
if (typeof value === "string") {
252+
return createIdentifier(value);
253+
}
254+
else {
255+
return value;
256+
}
257+
}
258+
259+
function coerceExpression(value: string | number | boolean | Expression): Expression {
260+
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
261+
return createLiteral(value);
262+
}
263+
else if (value === null) {
264+
return createLiteral(null);
265+
}
266+
else {
267+
return value;
268+
}
269+
}
270+
271+
const enum BinaryOperand {
272+
Left,
273+
Right
274+
}
275+
276+
function parenthesizeForBinary(operand: Expression, operator: SyntaxKind, side: BinaryOperand) {
277+
// When diagnosing whether the expression needs parentheses, the decision should be based
278+
// on the innermost expression in a chain of nested type assertions.
279+
while (operand.kind === SyntaxKind.TypeAssertionExpression || operand.kind === SyntaxKind.AsExpression) {
280+
operand = (<AssertionExpression>operand).expression;
281+
}
282+
283+
// If the resulting expression is already parenthesized, we do not need to do any further processing.
284+
if (operand.kind === SyntaxKind.ParenthesizedExpression) {
285+
return operand;
286+
}
287+
288+
return needsParenthesesForBinary(operand, operator, side)
289+
? parenthesizeExpression(operand)
290+
: operand;
291+
}
292+
293+
function needsParenthesesForBinary(operand: Expression, operator: SyntaxKind, side: BinaryOperand) {
294+
const operandPrecedence = getExpressionPrecedence(operand);
295+
const operatorPrecedence = getOperatorPrecedence(SyntaxKind.BinaryExpression, operator);
296+
switch (compareValues(operandPrecedence, operatorPrecedence)) {
297+
case Comparison.LessThan:
298+
return true;
299+
case Comparison.EqualTo:
300+
return isRightAssociativeOperandOnLeftHandSide(operand, side)
301+
|| isModuloOperandOnRightHandSide(operand, operator, side);
302+
case Comparison.GreaterThan:
303+
return false;
304+
}
305+
}
306+
307+
function isRightAssociativeOperandOnLeftHandSide(operand: Expression, side: BinaryOperand) {
308+
return side === BinaryOperand.Left
309+
&& getExpressionAssociativity(operand) === Associativity.Right;
310+
}
311+
312+
function isModuloOperandOnRightHandSide(operand: Expression, operator: SyntaxKind, side: BinaryOperand) {
313+
return side === BinaryOperand.Right
314+
&& operator !== SyntaxKind.PercentToken
315+
&& operand.kind === SyntaxKind.BinaryExpression
316+
&& (<BinaryExpression>operand).operatorToken.kind === SyntaxKind.PercentToken;
317+
}
318+
319+
function parenthesizeForAccess(expr: Expression): LeftHandSideExpression {
320+
// When diagnosing whether the expression needs parentheses, the decision should be based
321+
// on the innermost expression in a chain of nested type assertions.
322+
while (expr.kind === SyntaxKind.TypeAssertionExpression || expr.kind === SyntaxKind.AsExpression) {
323+
expr = (<AssertionExpression>expr).expression;
324+
}
325+
326+
// isLeftHandSideExpression is almost the correct criterion for when it is not necessary
327+
// to parenthesize the expression before a dot. The known exceptions are:
328+
//
329+
// NewExpression:
330+
// new C.x -> not the same as (new C).x
331+
// NumberLiteral
332+
// 1.x -> not the same as (1).x
333+
//
334+
if (isLeftHandSideExpression(expr) &&
335+
expr.kind !== SyntaxKind.NewExpression &&
336+
expr.kind !== SyntaxKind.NumericLiteral) {
337+
338+
return <LeftHandSideExpression>expr;
339+
}
340+
341+
return parenthesizeExpression(expr);
342+
}
138343
}

src/compiler/parser.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,18 @@
55
namespace ts {
66
/* @internal */ export let parseTime = 0;
77

8+
let NodeConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node;
9+
let SourceFileConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node;
10+
11+
export function createNode(kind: SyntaxKind, pos?: number, end?: number): Node {
12+
if (kind === SyntaxKind.SourceFile) {
13+
return new (SourceFileConstructor || (SourceFileConstructor = objectAllocator.getSourceFileConstructor()))(kind, pos, end);
14+
}
15+
else {
16+
return new (NodeConstructor || (NodeConstructor = objectAllocator.getNodeConstructor()))(kind, pos, end);
17+
}
18+
}
19+
820
function visitNode<T>(cbNode: (node: Node) => T, node: Node): T {
921
if (node) {
1022
return cbNode(node);

0 commit comments

Comments
 (0)