11/// <reference path="core.ts"/>
22/// <reference path="utilities.ts"/>
33
4+ /* @internal */
45namespace 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}
0 commit comments