2015-02-03 00:30:33 +01:00
//// [parserRealSource11.ts]
// Copyright (c) Microsoft. All rights reserved. Licensed under the Apache License, Version 2.0.
// See LICENSE.txt in the project root for complete license information.
///<reference path='typescript.ts' />
module TypeScript {
export class ASTSpan {
public minChar : number = - 1 ; // -1 = "undefined" or "compiler generated"
public limChar : number = - 1 ; // -1 = "undefined" or "compiler generated"
}
export class AST extends ASTSpan {
public type : Type = null ;
public flags = ASTFlags . Writeable ;
// REVIEW: for diagnostic purposes
public passCreated : number = CompilerDiagnostics . analysisPass ;
public preComments : Comment [ ] = null ;
public postComments : Comment [ ] = null ;
public isParenthesized = false ;
constructor ( public nodeType : NodeType ) {
super ( ) ;
}
public isExpression ( ) { return false ; }
public isStatementOrExpression ( ) { return false ; }
public isCompoundStatement ( ) { return false ; }
public isLeaf ( ) { return this . isStatementOrExpression ( ) && ( ! this . isCompoundStatement ( ) ) ; }
public typeCheck ( typeFlow : TypeFlow ) {
switch ( this . nodeType ) {
case NodeType . Error :
case NodeType . EmptyExpr :
this . type = typeFlow . anyType ;
break ;
case NodeType . This :
return typeFlow . typeCheckThis ( this ) ;
case NodeType . Null :
this . type = typeFlow . nullType ;
break ;
case NodeType . False :
case NodeType . True :
this . type = typeFlow . booleanType ;
break ;
case NodeType . Super :
return typeFlow . typeCheckSuper ( this ) ;
case NodeType . EndCode :
case NodeType . Empty :
case NodeType . Void :
this . type = typeFlow . voidType ;
break ;
default :
throw new Error ( "please implement in derived class" ) ;
}
return this ;
}
public emit ( emitter : Emitter , tokenId : TokenID , startLine : boolean ) {
emitter . emitParensAndCommentsInPlace ( this , true ) ;
switch ( this . nodeType ) {
case NodeType . This :
emitter . recordSourceMappingStart ( this ) ;
if ( emitter . thisFnc && ( hasFlag ( emitter . thisFnc . fncFlags , FncFlags . IsFatArrowFunction ) ) ) {
emitter . writeToOutput ( "_this" ) ;
}
else {
emitter . writeToOutput ( "this" ) ;
}
emitter . recordSourceMappingEnd ( this ) ;
break ;
case NodeType . Null :
emitter . recordSourceMappingStart ( this ) ;
emitter . writeToOutput ( "null" ) ;
emitter . recordSourceMappingEnd ( this ) ;
break ;
case NodeType . False :
emitter . recordSourceMappingStart ( this ) ;
emitter . writeToOutput ( "false" ) ;
emitter . recordSourceMappingEnd ( this ) ;
break ;
case NodeType . True :
emitter . recordSourceMappingStart ( this ) ;
emitter . writeToOutput ( "true" ) ;
emitter . recordSourceMappingEnd ( this ) ;
break ;
case NodeType . Super :
emitter . recordSourceMappingStart ( this ) ;
emitter . emitSuperReference ( ) ;
emitter . recordSourceMappingEnd ( this ) ;
break ;
case NodeType . EndCode :
break ;
case NodeType . Error :
case NodeType . EmptyExpr :
break ;
case NodeType . Empty :
emitter . recordSourceMappingStart ( this ) ;
emitter . writeToOutput ( "; " ) ;
emitter . recordSourceMappingEnd ( this ) ;
break ;
case NodeType . Void :
emitter . recordSourceMappingStart ( this ) ;
emitter . writeToOutput ( "void " ) ;
emitter . recordSourceMappingEnd ( this ) ;
break ;
default :
throw new Error ( "please implement in derived class" ) ;
}
emitter . emitParensAndCommentsInPlace ( this , false ) ;
}
public print ( context : PrintContext ) {
context . startLine ( ) ;
var lineCol = { line : - 1 , col : - 1 } ;
var limLineCol = { line : - 1 , col : - 1 } ;
if ( context . parser !== null ) {
context . parser . getSourceLineCol ( lineCol , this . minChar ) ;
context . parser . getSourceLineCol ( limLineCol , this . limChar ) ;
context . write ( "(" + lineCol . line + "," + lineCol . col + ")--" +
"(" + limLineCol . line + "," + limLineCol . col + "): " ) ;
}
var lab = this . printLabel ( ) ;
if ( hasFlag ( this . flags , ASTFlags . Error ) ) {
lab += " (Error)" ;
}
context . writeLine ( lab ) ;
}
public printLabel ( ) {
if ( nodeTypeTable [ this . nodeType ] !== undefined ) {
return nodeTypeTable [ this . nodeType ] ;
}
else {
return ( < any > NodeType ) . _map [ this . nodeType ] ;
}
}
public addToControlFlow ( context : ControlFlowContext ) : void {
// by default, AST adds itself to current basic block and does not check its children
context . walker . options . goChildren = false ;
context . addContent ( this ) ;
}
public netFreeUses ( container : Symbol , freeUses : StringHashTable ) {
}
public treeViewLabel ( ) {
return ( < any > NodeType ) . _map [ this . nodeType ] ;
}
public static getResolvedIdentifierName ( name : string ) : string {
if ( ! name ) return "" ;
var resolved = "" ;
var start = 0 ;
var i = 0 ;
while ( i <= name . length - 6 ) {
// Look for escape sequence \uxxxx
if ( name . charAt ( i ) == '\\' && name . charAt ( i + 1 ) == 'u' ) {
var charCode = parseInt ( name . substr ( i + 2 , 4 ) , 16 ) ;
resolved += name . substr ( start , i - start ) ;
resolved += String . fromCharCode ( charCode ) ;
i += 6 ;
start = i ;
continue ;
}
i ++ ;
}
// Append remaining string
resolved += name . substring ( start ) ;
return resolved ;
}
}
export class IncompleteAST extends AST {
constructor ( min : number , lim : number ) {
super ( NodeType . Error ) ;
this . minChar = min ;
this . limChar = lim ;
}
}
export class ASTList extends AST {
public enclosingScope : SymbolScope = null ;
public members : AST [ ] = new AST [ ] ;
constructor ( ) {
super ( NodeType . List ) ;
}
public addToControlFlow ( context : ControlFlowContext ) {
var len = this . members . length ;
for ( var i = 0 ; i < len ; i ++ ) {
if ( context . noContinuation ) {
context . addUnreachable ( this . members [ i ] ) ;
break ;
}
else {
this . members [ i ] = context . walk ( this . members [ i ] , this ) ;
}
}
context . walker . options . goChildren = false ;
}
public append ( ast : AST ) {
this . members [ this . members . length ] = ast ;
return this ;
}
public appendAll ( ast : AST ) {
if ( ast . nodeType == NodeType . List ) {
var list = < ASTList > ast ;
for ( var i = 0 , len = list . members . length ; i < len ; i ++ ) {
this . append ( list . members [ i ] ) ;
}
}
else {
this . append ( ast ) ;
}
return this ;
}
public emit ( emitter : Emitter , tokenId : TokenID , startLine : boolean ) {
emitter . recordSourceMappingStart ( this ) ;
emitter . emitJavascriptList ( this , null , TokenID . Semicolon , startLine , false , false ) ;
emitter . recordSourceMappingEnd ( this ) ;
}
public typeCheck ( typeFlow : TypeFlow ) {
var len = this . members . length ;
typeFlow . nestingLevel ++ ;
for ( var i = 0 ; i < len ; i ++ ) {
if ( this . members [ i ] ) {
this . members [ i ] = this . members [ i ] . typeCheck ( typeFlow ) ;
}
}
typeFlow . nestingLevel -- ;
return this ;
}
}
export class Identifier extends AST {
public sym : Symbol = null ;
public cloId = - 1 ;
public text : string ;
// 'actualText' is the text that the user has entered for the identifier. the text might
// include any Unicode escape sequences (e.g.: \u0041 for 'A'). 'text', however, contains
// the resolved value of any escape sequences in the actual text; so in the previous
// example, actualText = '\u0041', text = 'A'.
//
// For purposes of finding a symbol, use text, as this will allow you to match all
// variations of the variable text. For full-fidelity translation of the user input, such
// as emitting, use the actualText field.
//
// Note:
// To change text, and to avoid running into a situation where 'actualText' does not
// match 'text', always use setText.
constructor ( public actualText : string , public hasEscapeSequence ? : boolean ) {
super ( NodeType . Name ) ;
this . setText ( actualText , hasEscapeSequence ) ;
}
public setText ( actualText : string , hasEscapeSequence ? : boolean ) {
this . actualText = actualText ;
if ( hasEscapeSequence ) {
this . text = AST . getResolvedIdentifierName ( actualText ) ;
}
else {
this . text = actualText ;
}
}
public isMissing ( ) { return false ; }
public isLeaf ( ) { return true ; }
public treeViewLabel ( ) {
return "id: " + this . actualText ;
}
public printLabel ( ) {
if ( this . actualText ) {
return "id: " + this . actualText ;
}
else {
return "name node" ;
}
}
public typeCheck ( typeFlow : TypeFlow ) {
return typeFlow . typeCheckName ( this ) ;
}
public emit ( emitter : Emitter , tokenId : TokenID , startLine : boolean ) {
emitter . emitJavascriptName ( this , true ) ;
}
public static fromToken ( token : Token ) : Identifier {
return new Identifier ( token . getText ( ) , ( < IdentifierToken > token ) . hasEscapeSequence ) ;
}
}
export class MissingIdentifier extends Identifier {
constructor ( ) {
super ( "__missing" ) ;
}
public isMissing ( ) {
return true ;
}
public emit ( emitter : Emitter , tokenId : TokenID , startLine : boolean ) {
// Emit nothing for a missing ID
}
}
export class Label extends AST {
constructor ( public id : Identifier ) {
super ( NodeType . Label ) ;
}
public printLabel ( ) { return this . id . actualText + ":" ; }
public typeCheck ( typeFlow : TypeFlow ) {
this . type = typeFlow . voidType ;
return this ;
}
public emit ( emitter : Emitter , tokenId : TokenID , startLine : boolean ) {
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . recordSourceMappingStart ( this ) ;
emitter . recordSourceMappingStart ( this . id ) ;
emitter . writeToOutput ( this . id . actualText ) ;
emitter . recordSourceMappingEnd ( this . id ) ;
emitter . writeLineToOutput ( ":" ) ;
emitter . recordSourceMappingEnd ( this ) ;
emitter . emitParensAndCommentsInPlace ( this , false ) ;
}
}
export class Expression extends AST {
constructor ( nodeType : NodeType ) {
super ( nodeType ) ;
}
public isExpression ( ) { return true ; }
public isStatementOrExpression ( ) { return true ; }
}
export class UnaryExpression extends Expression {
public targetType : Type = null ; // Target type for an object literal (null if no target type)
public castTerm : AST = null ;
constructor ( nodeType : NodeType , public operand : AST ) {
super ( nodeType ) ;
}
public addToControlFlow ( context : ControlFlowContext ) : void {
super . addToControlFlow ( context ) ;
// TODO: add successor as catch block/finally block if present
if ( this . nodeType == NodeType . Throw ) {
context . returnStmt ( ) ;
}
}
public typeCheck ( typeFlow : TypeFlow ) {
switch ( this . nodeType ) {
case NodeType . Not :
return typeFlow . typeCheckBitNot ( this ) ;
case NodeType . LogNot :
return typeFlow . typeCheckLogNot ( this ) ;
case NodeType . Pos :
case NodeType . Neg :
return typeFlow . typeCheckUnaryNumberOperator ( this ) ;
case NodeType . IncPost :
case NodeType . IncPre :
case NodeType . DecPost :
case NodeType . DecPre :
return typeFlow . typeCheckIncOrDec ( this ) ;
case NodeType . ArrayLit :
typeFlow . typeCheckArrayLit ( this ) ;
return this ;
case NodeType . ObjectLit :
typeFlow . typeCheckObjectLit ( this ) ;
return this ;
case NodeType . Throw :
this . operand = typeFlow . typeCheck ( this . operand ) ;
this . type = typeFlow . voidType ;
return this ;
case NodeType . Typeof :
this . operand = typeFlow . typeCheck ( this . operand ) ;
this . type = typeFlow . stringType ;
return this ;
case NodeType . Delete :
this . operand = typeFlow . typeCheck ( this . operand ) ;
this . type = typeFlow . booleanType ;
break ;
case NodeType . TypeAssertion :
this . castTerm = typeFlow . typeCheck ( this . castTerm ) ;
var applyTargetType = ! this . operand . isParenthesized ;
var targetType = applyTargetType ? this . castTerm . type : null ;
typeFlow . checker . typeCheckWithContextualType ( targetType , typeFlow . checker . inProvisionalTypecheckMode ( ) , true , this . operand ) ;
typeFlow . castWithCoercion ( this . operand , this . castTerm . type , false , true ) ;
this . type = this . castTerm . type ;
return this ;
case NodeType . Void :
// REVIEW - Although this is good to do for completeness's sake,
// this shouldn't be strictly necessary from the void operator's
// point of view
this . operand = typeFlow . typeCheck ( this . operand ) ;
this . type = typeFlow . checker . undefinedType ;
break ;
default :
throw new Error ( "please implement in derived class" ) ;
}
return this ;
}
public emit ( emitter : Emitter , tokenId : TokenID , startLine : boolean ) {
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . recordSourceMappingStart ( this ) ;
switch ( this . nodeType ) {
case NodeType . IncPost :
emitter . emitJavascript ( this . operand , TokenID . PlusPlus , false ) ;
emitter . writeToOutput ( "++" ) ;
break ;
case NodeType . LogNot :
emitter . writeToOutput ( "!" ) ;
emitter . emitJavascript ( this . operand , TokenID . Exclamation , false ) ;
break ;
case NodeType . DecPost :
emitter . emitJavascript ( this . operand , TokenID . MinusMinus , false ) ;
emitter . writeToOutput ( "--" ) ;
break ;
case NodeType . ObjectLit :
emitter . emitObjectLiteral ( < ASTList > this . operand ) ;
break ;
case NodeType . ArrayLit :
emitter . emitArrayLiteral ( < ASTList > this . operand ) ;
break ;
case NodeType . Not :
emitter . writeToOutput ( "~" ) ;
emitter . emitJavascript ( this . operand , TokenID . Tilde , false ) ;
break ;
case NodeType . Neg :
emitter . writeToOutput ( "-" ) ;
if ( this . operand . nodeType == NodeType . Neg ) {
this . operand . isParenthesized = true ;
}
emitter . emitJavascript ( this . operand , TokenID . Minus , false ) ;
break ;
case NodeType . Pos :
emitter . writeToOutput ( "+" ) ;
if ( this . operand . nodeType == NodeType . Pos ) {
this . operand . isParenthesized = true ;
}
emitter . emitJavascript ( this . operand , TokenID . Plus , false ) ;
break ;
case NodeType . IncPre :
emitter . writeToOutput ( "++" ) ;
emitter . emitJavascript ( this . operand , TokenID . PlusPlus , false ) ;
break ;
case NodeType . DecPre :
emitter . writeToOutput ( "--" ) ;
emitter . emitJavascript ( this . operand , TokenID . MinusMinus , false ) ;
break ;
case NodeType . Throw :
emitter . writeToOutput ( "throw " ) ;
emitter . emitJavascript ( this . operand , TokenID . Tilde , false ) ;
emitter . writeToOutput ( ";" ) ;
break ;
case NodeType . Typeof :
emitter . writeToOutput ( "typeof " ) ;
emitter . emitJavascript ( this . operand , TokenID . Tilde , false ) ;
break ;
case NodeType . Delete :
emitter . writeToOutput ( "delete " ) ;
emitter . emitJavascript ( this . operand , TokenID . Tilde , false ) ;
break ;
case NodeType . Void :
emitter . writeToOutput ( "void " ) ;
emitter . emitJavascript ( this . operand , TokenID . Tilde , false ) ;
break ;
case NodeType . TypeAssertion :
emitter . emitJavascript ( this . operand , TokenID . Tilde , false ) ;
break ;
default :
throw new Error ( "please implement in derived class" ) ;
}
emitter . recordSourceMappingEnd ( this ) ;
emitter . emitParensAndCommentsInPlace ( this , false ) ;
}
}
export class CallExpression extends Expression {
constructor ( nodeType : NodeType ,
public target : AST ,
public arguments : ASTList ) {
super ( nodeType ) ;
this . minChar = this . target . minChar ;
}
public signature : Signature = null ;
public typeCheck ( typeFlow : TypeFlow ) {
if ( this . nodeType == NodeType . New ) {
return typeFlow . typeCheckNew ( this ) ;
}
else {
return typeFlow . typeCheckCall ( this ) ;
}
}
public emit ( emitter : Emitter , tokenId : TokenID , startLine : boolean ) {
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . recordSourceMappingStart ( this ) ;
if ( this . nodeType == NodeType . New ) {
emitter . emitNew ( this . target , this . arguments ) ;
}
else {
emitter . emitCall ( this , this . target , this . arguments ) ;
}
emitter . recordSourceMappingEnd ( this ) ;
emitter . emitParensAndCommentsInPlace ( this , false ) ;
}
}
export class BinaryExpression extends Expression {
constructor ( nodeType : NodeType , public operand1 : AST , public operand2 : AST ) {
super ( nodeType ) ;
}
public typeCheck ( typeFlow : TypeFlow ) {
switch ( this . nodeType ) {
case NodeType . Dot :
return typeFlow . typeCheckDotOperator ( this ) ;
case NodeType . Asg :
return typeFlow . typeCheckAsgOperator ( this ) ;
case NodeType . Add :
case NodeType . Sub :
case NodeType . Mul :
case NodeType . Div :
case NodeType . Mod :
case NodeType . Or :
case NodeType . And :
return typeFlow . typeCheckArithmeticOperator ( this , false ) ;
case NodeType . Xor :
return typeFlow . typeCheckBitwiseOperator ( this , false ) ;
case NodeType . Ne :
case NodeType . Eq :
var text : string ;
if ( typeFlow . checker . styleSettings . eqeqeq ) {
text = nodeTypeTable [ this . nodeType ] ;
typeFlow . checker . errorReporter . styleError ( this , "use of " + text ) ;
}
else if ( typeFlow . checker . styleSettings . eqnull ) {
text = nodeTypeTable [ this . nodeType ] ;
if ( ( this . operand2 !== null ) && ( this . operand2 . nodeType == NodeType . Null ) ) {
typeFlow . checker . errorReporter . styleError ( this , "use of " + text + " to compare with null" ) ;
}
}
case NodeType . Eqv :
case NodeType . NEqv :
case NodeType . Lt :
case NodeType . Le :
case NodeType . Ge :
case NodeType . Gt :
return typeFlow . typeCheckBooleanOperator ( this ) ;
case NodeType . Index :
return typeFlow . typeCheckIndex ( this ) ;
case NodeType . Member :
this . type = typeFlow . voidType ;
return this ;
case NodeType . LogOr :
return typeFlow . typeCheckLogOr ( this ) ;
case NodeType . LogAnd :
return typeFlow . typeCheckLogAnd ( this ) ;
case NodeType . AsgAdd :
case NodeType . AsgSub :
case NodeType . AsgMul :
case NodeType . AsgDiv :
case NodeType . AsgMod :
case NodeType . AsgOr :
case NodeType . AsgAnd :
return typeFlow . typeCheckArithmeticOperator ( this , true ) ;
case NodeType . AsgXor :
return typeFlow . typeCheckBitwiseOperator ( this , true ) ;
case NodeType . Lsh :
case NodeType . Rsh :
case NodeType . Rs2 :
return typeFlow . typeCheckShift ( this , false ) ;
case NodeType . AsgLsh :
case NodeType . AsgRsh :
case NodeType . AsgRs2 :
return typeFlow . typeCheckShift ( this , true ) ;
case NodeType . Comma :
return typeFlow . typeCheckCommaOperator ( this ) ;
case NodeType . InstOf :
return typeFlow . typeCheckInstOf ( this ) ;
case NodeType . In :
return typeFlow . typeCheckInOperator ( this ) ;
case NodeType . From :
typeFlow . checker . errorReporter . simpleError ( this , "Illegal use of 'from' keyword in binary expression" ) ;
break ;
default :
throw new Error ( "please implement in derived class" ) ;
}
return this ;
}
public emit ( emitter : Emitter , tokenId : TokenID , startLine : boolean ) {
var binTokenId = nodeTypeToTokTable [ this . nodeType ] ;
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . recordSourceMappingStart ( this ) ;
if ( binTokenId != undefined ) {
emitter . emitJavascript ( this . operand1 , binTokenId , false ) ;
if ( tokenTable [ binTokenId ] . text == "instanceof" ) {
emitter . writeToOutput ( " instanceof " ) ;
}
else if ( tokenTable [ binTokenId ] . text == "in" ) {
emitter . writeToOutput ( " in " ) ;
}
else {
emitter . writeToOutputTrimmable ( " " + tokenTable [ binTokenId ] . text + " " ) ;
}
emitter . emitJavascript ( this . operand2 , binTokenId , false ) ;
}
else {
switch ( this . nodeType ) {
case NodeType . Dot :
if ( ! emitter . tryEmitConstant ( this ) ) {
emitter . emitJavascript ( this . operand1 , TokenID . Dot , false ) ;
emitter . writeToOutput ( "." ) ;
emitter . emitJavascriptName ( < Identifier > this . operand2 , false ) ;
}
break ;
case NodeType . Index :
emitter . emitIndex ( this . operand1 , this . operand2 ) ;
break ;
case NodeType . Member :
if ( this . operand2 . nodeType == NodeType . FuncDecl && ( < FuncDecl > this . operand2 ) . isAccessor ( ) ) {
var funcDecl = < FuncDecl > this . operand2 ;
if ( hasFlag ( funcDecl . fncFlags , FncFlags . GetAccessor ) ) {
emitter . writeToOutput ( "get " ) ;
}
else {
emitter . writeToOutput ( "set " ) ;
}
emitter . emitJavascript ( this . operand1 , TokenID . Colon , false ) ;
}
else {
emitter . emitJavascript ( this . operand1 , TokenID . Colon , false ) ;
emitter . writeToOutputTrimmable ( ": " ) ;
}
emitter . emitJavascript ( this . operand2 , TokenID . Comma , false ) ;
break ;
case NodeType . Comma :
emitter . emitJavascript ( this . operand1 , TokenID . Comma , false ) ;
if ( emitter . emitState . inObjectLiteral ) {
emitter . writeLineToOutput ( ", " ) ;
}
else {
emitter . writeToOutput ( "," ) ;
}
emitter . emitJavascript ( this . operand2 , TokenID . Comma , false ) ;
break ;
case NodeType . Is :
throw new Error ( "should be de-sugared during type check" ) ;
default :
throw new Error ( "please implement in derived class" ) ;
}
}
emitter . recordSourceMappingEnd ( this ) ;
emitter . emitParensAndCommentsInPlace ( this , false ) ;
}
}
export class ConditionalExpression extends Expression {
constructor ( public operand1 : AST ,
public operand2 : AST ,
public operand3 : AST ) {
super ( NodeType . ConditionalExpression ) ;
}
public typeCheck ( typeFlow : TypeFlow ) {
return typeFlow . typeCheckQMark ( this ) ;
}
public emit ( emitter : Emitter , tokenId : TokenID , startLine : boolean ) {
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . recordSourceMappingStart ( this ) ;
emitter . emitJavascript ( this . operand1 , TokenID . Question , false ) ;
emitter . writeToOutput ( " ? " ) ;
emitter . emitJavascript ( this . operand2 , TokenID . Question , false ) ;
emitter . writeToOutput ( " : " ) ;
emitter . emitJavascript ( this . operand3 , TokenID . Question , false ) ;
emitter . recordSourceMappingEnd ( this ) ;
emitter . emitParensAndCommentsInPlace ( this , false ) ;
}
}
export class NumberLiteral extends Expression {
constructor ( public value : number , public hasEmptyFraction ? : boolean ) {
super ( NodeType . NumberLit ) ;
}
public isNegativeZero = false ;
public typeCheck ( typeFlow : TypeFlow ) {
this . type = typeFlow . doubleType ;
return this ;
}
public treeViewLabel ( ) {
return "num: " + this . printLabel ( ) ;
}
public emit ( emitter : Emitter , tokenId : TokenID , startLine : boolean ) {
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . recordSourceMappingStart ( this ) ;
if ( this . isNegativeZero ) {
emitter . writeToOutput ( "-" ) ;
}
emitter . writeToOutput ( this . value . toString ( ) ) ;
if ( this . hasEmptyFraction )
emitter . writeToOutput ( ".0" ) ;
emitter . recordSourceMappingEnd ( this ) ;
emitter . emitParensAndCommentsInPlace ( this , false ) ;
}
public printLabel ( ) {
if ( Math . floor ( this . value ) != this . value ) {
return this . value . toFixed ( 2 ) . toString ( ) ;
}
else if ( this . hasEmptyFraction ) {
return this . value . toString ( ) + ".0" ;
}
else {
return this . value . toString ( ) ;
}
}
}
export class RegexLiteral extends Expression {
constructor ( public regex ) {
super ( NodeType . Regex ) ;
}
public typeCheck ( typeFlow : TypeFlow ) {
this . type = typeFlow . regexType ;
return this ;
}
public emit ( emitter : Emitter , tokenId : TokenID , startLine : boolean ) {
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . recordSourceMappingStart ( this ) ;
emitter . writeToOutput ( this . regex . toString ( ) ) ;
emitter . recordSourceMappingEnd ( this ) ;
emitter . emitParensAndCommentsInPlace ( this , false ) ;
}
}
export class StringLiteral extends Expression {
constructor ( public text : string ) {
super ( NodeType . QString ) ;
}
public emit ( emitter : Emitter , tokenId : TokenID , startLine : boolean ) {
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . recordSourceMappingStart ( this ) ;
emitter . emitStringLiteral ( this . text ) ;
emitter . recordSourceMappingEnd ( this ) ;
emitter . emitParensAndCommentsInPlace ( this , false ) ;
}
public typeCheck ( typeFlow : TypeFlow ) {
this . type = typeFlow . stringType ;
return this ;
}
public treeViewLabel ( ) {
return "st: " + this . text ;
}
public printLabel ( ) {
return this . text ;
}
}
export class ModuleElement extends AST {
constructor ( nodeType : NodeType ) {
super ( nodeType ) ;
}
}
export class ImportDeclaration extends ModuleElement {
public isStatementOrExpression ( ) { return true ; }
public varFlags = VarFlags . None ;
public isDynamicImport = false ;
constructor ( public id : Identifier , public alias : AST ) {
super ( NodeType . ImportDeclaration ) ;
}
public emit ( emitter : Emitter , tokenId : TokenID , startLine : boolean ) {
var mod = < ModuleType > this . alias . type ;
// REVIEW: Only modules may be aliased for now, though there's no real
// restriction on what the type symbol may be
if ( ! this . isDynamicImport || ( this . id . sym && ! ( < TypeSymbol > this . id . sym ) . onlyReferencedAsTypeRef ) ) {
var prevModAliasId = emitter . modAliasId ;
var prevFirstModAlias = emitter . firstModAlias ;
emitter . recordSourceMappingStart ( this ) ;
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . writeToOutput ( "var " + this . id . actualText + " = " ) ;
emitter . modAliasId = this . id . actualText ;
emitter . firstModAlias = this . firstAliasedModToString ( ) ;
emitter . emitJavascript ( this . alias , TokenID . Tilde , false ) ;
// the dynamic import case will insert the semi-colon automatically
if ( ! this . isDynamicImport ) {
emitter . writeToOutput ( ";" ) ;
}
emitter . emitParensAndCommentsInPlace ( this , false ) ;
emitter . recordSourceMappingEnd ( this ) ;
emitter . modAliasId = prevModAliasId ;
emitter . firstModAlias = prevFirstModAlias ;
}
}
public typeCheck ( typeFlow : TypeFlow ) {
return typeFlow . typeCheckImportDecl ( this ) ;
}
public getAliasName ( aliasAST ? : AST = this . alias ) : string {
if ( aliasAST . nodeType == NodeType . Name ) {
return ( < Identifier > aliasAST ) . actualText ;
} else {
var dotExpr = < BinaryExpression > aliasAST ;
return this . getAliasName ( dotExpr . operand1 ) + "." + this . getAliasName ( dotExpr . operand2 ) ;
}
}
public firstAliasedModToString ( ) {
if ( this . alias . nodeType == NodeType . Name ) {
return ( < Identifier > this . alias ) . actualText ;
}
else {
var dotExpr = < BinaryExpression > this . alias ;
var firstMod = < Identifier > dotExpr . operand1 ;
return firstMod . actualText ;
}
}
}
export class BoundDecl extends AST {
public init : AST = null ;
public typeExpr : AST = null ;
public varFlags = VarFlags . None ;
public sym : Symbol = null ;
constructor ( public id : Identifier , nodeType : NodeType , public nestingLevel : number ) {
super ( nodeType ) ;
}
public isStatementOrExpression ( ) { return true ; }
public isPrivate ( ) { return hasFlag ( this . varFlags , VarFlags . Private ) ; }
public isPublic ( ) { return hasFlag ( this . varFlags , VarFlags . Public ) ; }
public isProperty ( ) { return hasFlag ( this . varFlags , VarFlags . Property ) ; }
public typeCheck ( typeFlow : TypeFlow ) {
return typeFlow . typeCheckBoundDecl ( this ) ;
}
public printLabel ( ) {
return this . treeViewLabel ( ) ;
}
}
export class VarDecl extends BoundDecl {
constructor ( id : Identifier , nest : number ) {
super ( id , NodeType . VarDecl , nest ) ;
}
public isAmbient ( ) { return hasFlag ( this . varFlags , VarFlags . Ambient ) ; }
public isExported ( ) { return hasFlag ( this . varFlags , VarFlags . Exported ) ; }
public isStatic ( ) { return hasFlag ( this . varFlags , VarFlags . Static ) ; }
public emit ( emitter : Emitter , tokenId : TokenID , startLine : boolean ) {
emitter . emitJavascriptVarDecl ( this , tokenId ) ;
}
public treeViewLabel ( ) {
return "var " + this . id . actualText ;
}
}
export class ArgDecl extends BoundDecl {
constructor ( id : Identifier ) {
super ( id , NodeType . ArgDecl , 0 ) ;
}
public isOptional = false ;
public isOptionalArg ( ) { return this . isOptional || this . init ; }
public treeViewLabel ( ) {
return "arg: " + this . id . actualText ;
}
public parameterPropertySym : FieldSymbol = null ;
public emit ( emitter : Emitter , tokenId : TokenID , startLine : boolean ) {
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . recordSourceMappingStart ( this ) ;
emitter . writeToOutput ( this . id . actualText ) ;
emitter . recordSourceMappingEnd ( this ) ;
emitter . emitParensAndCommentsInPlace ( this , false ) ;
}
}
var internalId = 0 ;
export class FuncDecl extends AST {
public hint : string = null ;
public fncFlags = FncFlags . None ;
public returnTypeAnnotation : AST = null ;
public symbols : IHashTable ;
public variableArgList = false ;
public signature : Signature ;
public envids : Identifier [ ] ;
public jumpRefs : Identifier [ ] = null ;
public internalNameCache : string = null ;
public tmp1Declared = false ;
public enclosingFnc : FuncDecl = null ;
public freeVariables : Symbol [ ] = [ ] ;
public unitIndex = - 1 ;
public classDecl : NamedDeclaration = null ;
public boundToProperty : VarDecl = null ;
public isOverload = false ;
public innerStaticFuncs : FuncDecl [ ] = [ ] ;
public isTargetTypedAsMethod = false ;
public isInlineCallLiteral = false ;
public accessorSymbol : Symbol = null ;
public leftCurlyCount = 0 ;
public rightCurlyCount = 0 ;
public returnStatementsWithExpressions : ReturnStatement [ ] = [ ] ;
public scopeType : Type = null ; // Type of the FuncDecl, before target typing
public endingToken : ASTSpan = null ;
constructor ( public name : Identifier , public bod : ASTList , public isConstructor : boolean ,
public arguments : ASTList , public vars : ASTList , public scopes : ASTList , public statics : ASTList ,
nodeType : number ) {
super ( nodeType ) ;
}
public internalName ( ) : string {
if ( this . internalNameCache == null ) {
var extName = this . getNameText ( ) ;
if ( extName ) {
this . internalNameCache = "_internal_" + extName ;
}
else {
this . internalNameCache = "_internal_" + internalId ++ ;
}
}
return this . internalNameCache ;
}
public hasSelfReference ( ) { return hasFlag ( this . fncFlags , FncFlags . HasSelfReference ) ; }
public setHasSelfReference ( ) { this . fncFlags |= FncFlags . HasSelfReference ; }
public addCloRef ( id : Identifier , sym : Symbol ) : number {
if ( this . envids == null ) {
this . envids = new Identifier [ ] ;
}
this . envids [ this . envids . length ] = id ;
var outerFnc = this . enclosingFnc ;
if ( sym ) {
while ( outerFnc && ( outerFnc . type . symbol != sym . container ) ) {
outerFnc . addJumpRef ( sym ) ;
outerFnc = outerFnc . enclosingFnc ;
}
}
return this . envids . length - 1 ;
}
public addJumpRef ( sym : Symbol ) : void {
if ( this . jumpRefs == null ) {
this . jumpRefs = new Identifier [ ] ;
}
var id = new Identifier ( sym . name ) ;
this . jumpRefs [ this . jumpRefs . length ] = id ;
id . sym = sym ;
id . cloId = this . addCloRef ( id , null ) ;
}
public buildControlFlow ( ) : ControlFlowContext {
var entry = new BasicBlock ( ) ;
var exit = new BasicBlock ( ) ;
var context = new ControlFlowContext ( entry , exit ) ;
var controlFlowPrefix = ( ast : AST , parent : AST , walker : IAstWalker ) => {
ast . addToControlFlow ( walker . state ) ;
return ast ;
}
var walker = getAstWalkerFactory ( ) . getWalker ( controlFlowPrefix , null , null , context ) ;
context . walker = walker ;
walker . walk ( this . bod , this ) ;
return context ;
}
public typeCheck ( typeFlow : TypeFlow ) {
return typeFlow . typeCheckFunction ( this ) ;
}
public emit ( emitter : Emitter , tokenId : TokenID , startLine : boolean ) {
emitter . emitJavascriptFunction ( this ) ;
}
public getNameText ( ) {
if ( this . name ) {
return this . name . actualText ;
}
else {
return this . hint ;
}
}
public isMethod ( ) {
return ( this . fncFlags & FncFlags . Method ) != FncFlags . None ;
}
public isCallMember ( ) { return hasFlag ( this . fncFlags , FncFlags . CallMember ) ; }
public isConstructMember ( ) { return hasFlag ( this . fncFlags , FncFlags . ConstructMember ) ; }
public isIndexerMember ( ) { return hasFlag ( this . fncFlags , FncFlags . IndexerMember ) ; }
public isSpecialFn ( ) { return this . isCallMember ( ) || this . isIndexerMember ( ) || this . isConstructMember ( ) ; }
public isAnonymousFn ( ) { return this . name === null ; }
public isAccessor ( ) { return hasFlag ( this . fncFlags , FncFlags . GetAccessor ) || hasFlag ( this . fncFlags , FncFlags . SetAccessor ) ; }
public isGetAccessor ( ) { return hasFlag ( this . fncFlags , FncFlags . GetAccessor ) ; }
public isSetAccessor ( ) { return hasFlag ( this . fncFlags , FncFlags . SetAccessor ) ; }
public isAmbient ( ) { return hasFlag ( this . fncFlags , FncFlags . Ambient ) ; }
public isExported ( ) { return hasFlag ( this . fncFlags , FncFlags . Exported ) ; }
public isPrivate ( ) { return hasFlag ( this . fncFlags , FncFlags . Private ) ; }
public isPublic ( ) { return hasFlag ( this . fncFlags , FncFlags . Public ) ; }
public isStatic ( ) { return hasFlag ( this . fncFlags , FncFlags . Static ) ; }
public treeViewLabel ( ) {
if ( this . name == null ) {
return "funcExpr" ;
}
else {
return "func: " + this . name . actualText
}
}
public ClearFlags ( ) : void {
this . fncFlags = FncFlags . None ;
}
public isSignature ( ) { return ( this . fncFlags & FncFlags . Signature ) != FncFlags . None ; }
public hasStaticDeclarations ( ) { return ( ! this . isConstructor && ( this . statics . members . length > 0 || this . innerStaticFuncs . length > 0 ) ) ; }
}
export class LocationInfo {
constructor ( public filename : string , public lineMap : number [ ] , public unitIndex ) { }
}
export var unknownLocationInfo = new LocationInfo ( "unknown" , null , - 1 ) ;
export class Script extends FuncDecl {
public locationInfo : LocationInfo = null ;
public referencedFiles : IFileReference [ ] = [ ] ;
public requiresGlobal = false ;
public requiresInherits = false ;
public isResident = false ;
public isDeclareFile = false ;
public hasBeenTypeChecked = false ;
public topLevelMod : ModuleDeclaration = null ;
public leftCurlyCount = 0 ;
public rightCurlyCount = 0 ;
public vars : ASTList ;
public scopes : ASTList ;
// Remember if the script contains Unicode chars, that is needed when generating code for this script object to decide the output file correct encoding.
public containsUnicodeChar = false ;
public containsUnicodeCharInComment = false ;
constructor ( vars : ASTList , scopes : ASTList ) {
super ( new Identifier ( "script" ) , null , false , null , vars , scopes , null , NodeType . Script ) ;
this . vars = vars ;
this . scopes = scopes ;
}
public typeCheck ( typeFlow : TypeFlow ) {
return typeFlow . typeCheckScript ( this ) ;
}
public treeViewLabel ( ) {
return "Script" ;
}
public emitRequired ( ) {
if ( ! this . isDeclareFile && ! this . isResident && this . bod ) {
for ( var i = 0 , len = this . bod . members . length ; i < len ; i ++ ) {
var stmt = this . bod . members [ i ] ;
if ( stmt . nodeType == NodeType . ModuleDeclaration ) {
if ( ! hasFlag ( ( < ModuleDeclaration > stmt ) . modFlags , ModuleFlags . ShouldEmitModuleDecl | ModuleFlags . Ambient ) ) {
return true ;
}
}
else if ( stmt . nodeType == NodeType . ClassDeclaration ) {
if ( ! hasFlag ( ( < InterfaceDeclaration > stmt ) . varFlags , VarFlags . Ambient ) ) {
return true ;
}
}
else if ( stmt . nodeType == NodeType . VarDecl ) {
if ( ! hasFlag ( ( < VarDecl > stmt ) . varFlags , VarFlags . Ambient ) ) {
return true ;
}
}
else if ( stmt . nodeType == NodeType . FuncDecl ) {
if ( ! ( < FuncDecl > stmt ) . isSignature ( ) ) {
return true ;
}
}
else if ( stmt . nodeType != NodeType . InterfaceDeclaration && stmt . nodeType != NodeType . Empty ) {
return true ;
}
}
}
return false ;
}
public emit ( emitter : Emitter , tokenId : TokenID , startLine : boolean ) {
if ( this . emitRequired ( ) ) {
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . recordSourceMappingStart ( this ) ;
emitter . emitJavascriptList ( this . bod , null , TokenID . Semicolon , true , false , false , true , this . requiresInherits ) ;
emitter . recordSourceMappingEnd ( this ) ;
emitter . emitParensAndCommentsInPlace ( this , false ) ;
}
}
}
export class NamedDeclaration extends ModuleElement {
public leftCurlyCount = 0 ;
public rightCurlyCount = 0 ;
constructor ( nodeType : NodeType ,
public name : Identifier ,
public members : ASTList ) {
super ( nodeType ) ;
}
}
export class ModuleDeclaration extends NamedDeclaration {
public modFlags = ModuleFlags . ShouldEmitModuleDecl ;
public mod : ModuleType ;
public prettyName : string ;
public amdDependencies : string [ ] = [ ] ;
public vars : ASTList ;
public scopes : ASTList ;
// Remember if the module contains Unicode chars, that is needed for dynamic module as we will generate a file for each.
public containsUnicodeChar = false ;
public containsUnicodeCharInComment = false ;
constructor ( name : Identifier , members : ASTList , vars : ASTList , scopes : ASTList , public endingToken : ASTSpan ) {
super ( NodeType . ModuleDeclaration , name , members ) ;
this . vars = vars ;
this . scopes = scopes ;
this . prettyName = this . name . actualText ;
}
public isExported ( ) { return hasFlag ( this . modFlags , ModuleFlags . Exported ) ; }
public isAmbient ( ) { return hasFlag ( this . modFlags , ModuleFlags . Ambient ) ; }
public isEnum ( ) { return hasFlag ( this . modFlags , ModuleFlags . IsEnum ) ; }
public recordNonInterface ( ) {
this . modFlags &= ~ ModuleFlags . ShouldEmitModuleDecl ;
}
public typeCheck ( typeFlow : TypeFlow ) {
return typeFlow . typeCheckModule ( this ) ;
}
public emit ( emitter : Emitter , tokenId : TokenID , startLine : boolean ) {
if ( ! hasFlag ( this . modFlags , ModuleFlags . ShouldEmitModuleDecl ) ) {
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . recordSourceMappingStart ( this ) ;
emitter . emitJavascriptModule ( this ) ;
emitter . recordSourceMappingEnd ( this ) ;
emitter . emitParensAndCommentsInPlace ( this , false ) ;
}
}
}
export class TypeDeclaration extends NamedDeclaration {
public varFlags = VarFlags . None ;
constructor ( nodeType : NodeType ,
name : Identifier ,
public extendsList : ASTList ,
public implementsList : ASTList ,
members : ASTList ) {
super ( nodeType , name , members ) ;
}
public isExported ( ) {
return hasFlag ( this . varFlags , VarFlags . Exported ) ;
}
public isAmbient ( ) {
return hasFlag ( this . varFlags , VarFlags . Ambient ) ;
}
}
export class ClassDeclaration extends TypeDeclaration {
public knownMemberNames : any = { } ;
public constructorDecl : FuncDecl = null ;
public constructorNestingLevel = 0 ;
public endingToken : ASTSpan = null ;
constructor ( name : Identifier ,
members : ASTList ,
extendsList : ASTList ,
implementsList : ASTList ) {
super ( NodeType . ClassDeclaration , name , extendsList , implementsList , members ) ;
}
public typeCheck ( typeFlow : TypeFlow ) {
return typeFlow . typeCheckClass ( this ) ;
}
public emit ( emitter : Emitter , tokenId : TokenID , startLine : boolean ) {
emitter . emitJavascriptClass ( this ) ;
}
}
export class InterfaceDeclaration extends TypeDeclaration {
constructor ( name : Identifier ,
members : ASTList ,
extendsList : ASTList ,
implementsList : ASTList ) {
super ( NodeType . InterfaceDeclaration , name , extendsList , implementsList , members ) ;
}
public typeCheck ( typeFlow : TypeFlow ) {
return typeFlow . typeCheckInterface ( this ) ;
}
public emit ( emitter : Emitter , tokenId : TokenID , startLine : boolean ) {
}
}
export class Statement extends ModuleElement {
constructor ( nodeType : NodeType ) {
super ( nodeType ) ;
this . flags |= ASTFlags . IsStatement ;
}
public isLoop ( ) { return false ; }
public isStatementOrExpression ( ) { return true ; }
public isCompoundStatement ( ) { return this . isLoop ( ) ; }
public typeCheck ( typeFlow : TypeFlow ) {
this . type = typeFlow . voidType ;
return this ;
}
}
export class LabeledStatement extends Statement {
constructor ( public labels : ASTList , public stmt : AST ) {
super ( NodeType . LabeledStatement ) ;
}
public emit ( emitter : Emitter , tokenId : TokenID , startLine : boolean ) {
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . recordSourceMappingStart ( this ) ;
if ( this . labels ) {
var labelsLen = this . labels . members . length ;
for ( var i = 0 ; i < labelsLen ; i ++ ) {
this . labels . members [ i ] . emit ( emitter , tokenId , startLine ) ;
}
}
this . stmt . emit ( emitter , tokenId , true ) ;
emitter . recordSourceMappingEnd ( this ) ;
emitter . emitParensAndCommentsInPlace ( this , false ) ;
}
public typeCheck ( typeFlow : TypeFlow ) {
typeFlow . typeCheck ( this . labels ) ;
this . stmt = this . stmt . typeCheck ( typeFlow ) ;
return this ;
}
public addToControlFlow ( context : ControlFlowContext ) : void {
var beforeBB = context . current ;
var bb = new BasicBlock ( ) ;
context . current = bb ;
beforeBB . addSuccessor ( bb ) ;
}
}
export class Block extends Statement {
constructor ( public statements : ASTList ,
public isStatementBlock : boolean ) {
super ( NodeType . Block ) ;
}
public emit ( emitter : Emitter , tokenId : TokenID , startLine : boolean ) {
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . recordSourceMappingStart ( this ) ;
if ( this . isStatementBlock ) {
emitter . writeLineToOutput ( " {" ) ;
emitter . indenter . increaseIndent ( ) ;
} else {
emitter . setInVarBlock ( this . statements . members . length ) ;
}
var temp = emitter . setInObjectLiteral ( false ) ;
if ( this . statements ) {
emitter . emitJavascriptList ( this . statements , null , TokenID . Semicolon , true , false , false ) ;
}
if ( this . isStatementBlock ) {
emitter . indenter . decreaseIndent ( ) ;
emitter . emitIndent ( ) ;
emitter . writeToOutput ( "}" ) ;
}
emitter . setInObjectLiteral ( temp ) ;
emitter . recordSourceMappingEnd ( this ) ;
emitter . emitParensAndCommentsInPlace ( this , false ) ;
}
public addToControlFlow ( context : ControlFlowContext ) {
var afterIfNeeded = new BasicBlock ( ) ;
context . pushStatement ( this , context . current , afterIfNeeded ) ;
if ( this . statements ) {
context . walk ( this . statements , this ) ;
}
context . walker . options . goChildren = false ;
context . popStatement ( ) ;
if ( afterIfNeeded . predecessors . length > 0 ) {
context . current . addSuccessor ( afterIfNeeded ) ;
context . current = afterIfNeeded ;
}
}
public typeCheck ( typeFlow : TypeFlow ) {
if ( ! typeFlow . checker . styleSettings . emptyBlocks ) {
if ( ( this . statements === null ) || ( this . statements . members . length == 0 ) ) {
typeFlow . checker . errorReporter . styleError ( this , "empty block" ) ;
}
}
typeFlow . typeCheck ( this . statements ) ;
return this ;
}
}
export class Jump extends Statement {
public target : string = null ;
public hasExplicitTarget ( ) { return ( this . target ) ; }
public resolvedTarget : Statement = null ;
constructor ( nodeType : NodeType ) {
super ( nodeType ) ;
}
public setResolvedTarget ( parser : Parser , stmt : Statement ) : boolean {
if ( stmt . isLoop ( ) ) {
this . resolvedTarget = stmt ;
return true ;
}
if ( this . nodeType === NodeType . Continue ) {
parser . reportParseError ( "continue statement applies only to loops" ) ;
return false ;
}
else {
if ( ( stmt . nodeType == NodeType . Switch ) || this . hasExplicitTarget ( ) ) {
this . resolvedTarget = stmt ;
return true ;
}
else {
parser . reportParseError ( "break statement with no label can apply only to a loop or switch statement" ) ;
return false ;
}
}
}
public addToControlFlow ( context : ControlFlowContext ) : void {
super . addToControlFlow ( context ) ;
context . unconditionalBranch ( this . resolvedTarget , ( this . nodeType == NodeType . Continue ) ) ;
}
public emit ( emitter : Emitter , tokenId : TokenID , startLine : boolean ) {
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . recordSourceMappingStart ( this ) ;
if ( this . nodeType == NodeType . Break ) {
emitter . writeToOutput ( "break" ) ;
}
else {
emitter . writeToOutput ( "continue" ) ;
}
if ( this . hasExplicitTarget ( ) ) {
emitter . writeToOutput ( " " + this . target ) ;
}
emitter . recordSourceMappingEnd ( this ) ;
emitter . writeToOutput ( ";" ) ;
emitter . emitParensAndCommentsInPlace ( this , false ) ;
}
}
export class WhileStatement extends Statement {
public body : AST = null ;
constructor ( public cond : AST ) {
super ( NodeType . While ) ;
}
public isLoop ( ) { return true ; }
public emit ( emitter : Emitter , tokenId : TokenID , startLine : boolean ) {
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . recordSourceMappingStart ( this ) ;
var temp = emitter . setInObjectLiteral ( false ) ;
emitter . writeToOutput ( "while(" ) ;
emitter . emitJavascript ( this . cond , TokenID . While , false ) ;
emitter . writeToOutput ( ")" ) ;
emitter . emitJavascriptStatements ( this . body , false , false ) ;
emitter . setInObjectLiteral ( temp ) ;
emitter . recordSourceMappingEnd ( this ) ;
emitter . emitParensAndCommentsInPlace ( this , false ) ;
}
public typeCheck ( typeFlow : TypeFlow ) {
return typeFlow . typeCheckWhile ( this ) ;
}
public addToControlFlow ( context : ControlFlowContext ) : void {
var loopHeader = context . current ;
var loopStart = new BasicBlock ( ) ;
var afterLoop = new BasicBlock ( ) ;
loopHeader . addSuccessor ( loopStart ) ;
context . current = loopStart ;
context . addContent ( this . cond ) ;
var condBlock = context . current ;
var targetInfo : ITargetInfo = null ;
if ( this . body ) {
context . current = new BasicBlock ( ) ;
condBlock . addSuccessor ( context . current ) ;
context . pushStatement ( this , loopStart , afterLoop ) ;
context . walk ( this . body , this ) ;
targetInfo = context . popStatement ( ) ;
}
if ( ! ( context . noContinuation ) ) {
var loopEnd = context . current ;
loopEnd . addSuccessor ( loopStart ) ;
}
context . current = afterLoop ;
condBlock . addSuccessor ( afterLoop ) ;
// TODO: check for while (true) and then only continue if afterLoop has predecessors
context . noContinuation = false ;
context . walker . options . goChildren = false ;
}
}
export class DoWhileStatement extends Statement {
public body : AST = null ;
public whileAST : AST = null ;
public cond : AST = null ;
public isLoop ( ) { return true ; }
constructor ( ) {
super ( NodeType . DoWhile ) ;
}
public emit ( emitter : Emitter , tokenId : TokenID , startLine : boolean ) {
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . recordSourceMappingStart ( this ) ;
var temp = emitter . setInObjectLiteral ( false ) ;
emitter . writeToOutput ( "do" ) ;
emitter . emitJavascriptStatements ( this . body , true , false ) ;
emitter . recordSourceMappingStart ( this . whileAST ) ;
emitter . writeToOutput ( "while" ) ;
emitter . recordSourceMappingEnd ( this . whileAST ) ;
emitter . writeToOutput ( '(' ) ;
emitter . emitJavascript ( this . cond , TokenID . CloseParen , false ) ;
emitter . writeToOutput ( ")" ) ;
emitter . setInObjectLiteral ( temp ) ;
emitter . recordSourceMappingEnd ( this ) ;
emitter . emitParensAndCommentsInPlace ( this , false ) ;
}
public typeCheck ( typeFlow : TypeFlow ) {
return typeFlow . typeCheckDoWhile ( this ) ;
}
public addToControlFlow ( context : ControlFlowContext ) : void {
var loopHeader = context . current ;
var loopStart = new BasicBlock ( ) ;
var afterLoop = new BasicBlock ( ) ;
loopHeader . addSuccessor ( loopStart ) ;
context . current = loopStart ;
var targetInfo : ITargetInfo = null ;
if ( this . body ) {
context . pushStatement ( this , loopStart , afterLoop ) ;
context . walk ( this . body , this ) ;
targetInfo = context . popStatement ( ) ;
}
if ( ! ( context . noContinuation ) ) {
var loopEnd = context . current ;
loopEnd . addSuccessor ( loopStart ) ;
context . addContent ( this . cond ) ;
// TODO: check for while (true)
context . current = afterLoop ;
loopEnd . addSuccessor ( afterLoop ) ;
}
else {
context . addUnreachable ( this . cond ) ;
}
context . walker . options . goChildren = false ;
}
}
export class IfStatement extends Statement {
public thenBod : AST ;
public elseBod : AST = null ;
public statement : ASTSpan = new ASTSpan ( ) ;
constructor ( public cond : AST ) {
super ( NodeType . If ) ;
}
public isCompoundStatement ( ) { return true ; }
public emit ( emitter : Emitter , tokenId : TokenID , startLine : boolean ) {
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . recordSourceMappingStart ( this ) ;
var temp = emitter . setInObjectLiteral ( false ) ;
emitter . recordSourceMappingStart ( this . statement ) ;
emitter . writeToOutput ( "if(" ) ;
emitter . emitJavascript ( this . cond , TokenID . If , false ) ;
emitter . writeToOutput ( ")" ) ;
emitter . recordSourceMappingEnd ( this . statement ) ;
emitter . emitJavascriptStatements ( this . thenBod , true , false ) ;
if ( this . elseBod ) {
emitter . writeToOutput ( " else" ) ;
emitter . emitJavascriptStatements ( this . elseBod , true , true ) ;
}
emitter . setInObjectLiteral ( temp ) ;
emitter . recordSourceMappingEnd ( this ) ;
emitter . emitParensAndCommentsInPlace ( this , false ) ;
}
public typeCheck ( typeFlow : TypeFlow ) {
return typeFlow . typeCheckIf ( this ) ;
}
public addToControlFlow ( context : ControlFlowContext ) : void {
this . cond . addToControlFlow ( context ) ;
var afterIf = new BasicBlock ( ) ;
var beforeIf = context . current ;
context . pushStatement ( this , beforeIf , afterIf ) ;
var hasContinuation = false ;
context . current = new BasicBlock ( ) ;
beforeIf . addSuccessor ( context . current ) ;
context . walk ( this . thenBod , this ) ;
if ( ! context . noContinuation ) {
hasContinuation = true ;
context . current . addSuccessor ( afterIf ) ;
}
if ( this . elseBod ) {
// current block will be thenBod
context . current = new BasicBlock ( ) ;
context . noContinuation = false ;
beforeIf . addSuccessor ( context . current ) ;
context . walk ( this . elseBod , this ) ;
if ( ! context . noContinuation ) {
hasContinuation = true ;
context . current . addSuccessor ( afterIf ) ;
}
else {
// thenBod created continuation for if statement
if ( hasContinuation ) {
context . noContinuation = false ;
}
}
}
else {
beforeIf . addSuccessor ( afterIf ) ;
context . noContinuation = false ;
hasContinuation = true ;
}
var targetInfo = context . popStatement ( ) ;
if ( afterIf . predecessors . length > 0 ) {
context . noContinuation = false ;
hasContinuation = true ;
}
if ( hasContinuation ) {
context . current = afterIf ;
}
context . walker . options . goChildren = false ;
}
}
export class ReturnStatement extends Statement {
public returnExpression : AST = null ;
constructor ( ) {
super ( NodeType . Return ) ;
}
public emit ( emitter : Emitter , tokenId : TokenID , startLine : boolean ) {
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . recordSourceMappingStart ( this ) ;
var temp = emitter . setInObjectLiteral ( false ) ;
if ( this . returnExpression ) {
emitter . writeToOutput ( "return " ) ;
emitter . emitJavascript ( this . returnExpression , TokenID . Semicolon , false ) ;
}
else {
emitter . writeToOutput ( "return;" ) ;
}
emitter . setInObjectLiteral ( temp ) ;
emitter . recordSourceMappingEnd ( this ) ;
emitter . emitParensAndCommentsInPlace ( this , false ) ;
}
public addToControlFlow ( context : ControlFlowContext ) : void {
super . addToControlFlow ( context ) ;
context . returnStmt ( ) ;
}
public typeCheck ( typeFlow : TypeFlow ) {
return typeFlow . typeCheckReturn ( this ) ;
}
}
export class EndCode extends AST {
constructor ( ) {
super ( NodeType . EndCode ) ;
}
}
export class ForInStatement extends Statement {
constructor ( public lval : AST , public obj : AST ) {
super ( NodeType . ForIn ) ;
if ( this . lval && ( this . lval . nodeType == NodeType . VarDecl ) ) {
( < BoundDecl > this . lval ) . varFlags |= VarFlags . AutoInit ;
}
}
public statement : ASTSpan = new ASTSpan ( ) ;
public body : AST ;
public isLoop ( ) { return true ; }
public isFiltered ( ) {
if ( this . body ) {
var singleItem : AST = null ;
if ( this . body . nodeType == NodeType . List ) {
var stmts = < ASTList > this . body ;
if ( stmts . members . length == 1 ) {
singleItem = stmts . members [ 0 ] ;
}
}
else {
singleItem = this . body ;
}
// match template for filtering 'own' properties from obj
if ( singleItem !== null ) {
if ( singleItem . nodeType == NodeType . Block ) {
var block = < Block > singleItem ;
if ( ( block . statements !== null ) && ( block . statements . members . length == 1 ) ) {
singleItem = block . statements . members [ 0 ] ;
}
}
if ( singleItem . nodeType == NodeType . If ) {
var cond = ( < IfStatement > singleItem ) . cond ;
if ( cond . nodeType == NodeType . Call ) {
var target = ( < CallExpression > cond ) . target ;
if ( target . nodeType == NodeType . Dot ) {
var binex = < BinaryExpression > target ;
if ( ( binex . operand1 . nodeType == NodeType . Name ) &&
( this . obj . nodeType == NodeType . Name ) &&
( ( < Identifier > binex . operand1 ) . actualText == ( < Identifier > this . obj ) . actualText ) ) {
var prop = < Identifier > binex . operand2 ;
if ( prop . actualText == "hasOwnProperty" ) {
var args = ( < CallExpression > cond ) . arguments ;
if ( ( args !== null ) && ( args . members . length == 1 ) ) {
var arg = args . members [ 0 ] ;
if ( ( arg . nodeType == NodeType . Name ) &&
( this . lval . nodeType == NodeType . Name ) ) {
if ( ( ( < Identifier > this . lval ) . actualText ) == ( < Identifier > arg ) . actualText ) {
return true ;
}
}
}
}
}
}
}
}
}
}
return false ;
}
public emit ( emitter : Emitter , tokenId : TokenID , startLine : boolean ) {
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . recordSourceMappingStart ( this ) ;
var temp = emitter . setInObjectLiteral ( false ) ;
emitter . recordSourceMappingStart ( this . statement ) ;
emitter . writeToOutput ( "for(" ) ;
emitter . emitJavascript ( this . lval , TokenID . For , false ) ;
emitter . writeToOutput ( " in " ) ;
emitter . emitJavascript ( this . obj , TokenID . For , false ) ;
emitter . writeToOutput ( ")" ) ;
emitter . recordSourceMappingEnd ( this . statement ) ;
emitter . emitJavascriptStatements ( this . body , true , false ) ;
emitter . setInObjectLiteral ( temp ) ;
emitter . recordSourceMappingEnd ( this ) ;
emitter . emitParensAndCommentsInPlace ( this , false ) ;
}
public typeCheck ( typeFlow : TypeFlow ) {
if ( typeFlow . checker . styleSettings . forin ) {
if ( ! this . isFiltered ( ) ) {
typeFlow . checker . errorReporter . styleError ( this , "no hasOwnProperty filter" ) ;
}
}
return typeFlow . typeCheckForIn ( this ) ;
}
public addToControlFlow ( context : ControlFlowContext ) : void {
if ( this . lval ) {
context . addContent ( this . lval ) ;
}
if ( this . obj ) {
context . addContent ( this . obj ) ;
}
var loopHeader = context . current ;
var loopStart = new BasicBlock ( ) ;
var afterLoop = new BasicBlock ( ) ;
loopHeader . addSuccessor ( loopStart ) ;
context . current = loopStart ;
if ( this . body ) {
context . pushStatement ( this , loopStart , afterLoop ) ;
context . walk ( this . body , this ) ;
context . popStatement ( ) ;
}
if ( ! ( context . noContinuation ) ) {
var loopEnd = context . current ;
loopEnd . addSuccessor ( loopStart ) ;
}
context . current = afterLoop ;
context . noContinuation = false ;
loopHeader . addSuccessor ( afterLoop ) ;
context . walker . options . goChildren = false ;
}
}
export class ForStatement extends Statement {
public cond : AST ;
public body : AST ;
public incr : AST ;
constructor ( public init : AST ) {
super ( NodeType . For ) ;
}
public isLoop ( ) { return true ; }
public emit ( emitter : Emitter , tokenId : TokenID , startLine : boolean ) {
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . recordSourceMappingStart ( this ) ;
var temp = emitter . setInObjectLiteral ( false ) ;
emitter . writeToOutput ( "for(" ) ;
if ( this . init ) {
if ( this . init . nodeType != NodeType . List ) {
emitter . emitJavascript ( this . init , TokenID . For , false ) ;
}
else {
emitter . setInVarBlock ( ( < ASTList > this . init ) . members . length ) ;
emitter . emitJavascriptList ( this . init , null , TokenID . For , false , false , false ) ;
}
}
emitter . writeToOutput ( "; " ) ;
emitter . emitJavascript ( this . cond , TokenID . For , false ) ;
emitter . writeToOutput ( "; " ) ;
emitter . emitJavascript ( this . incr , TokenID . For , false ) ;
emitter . writeToOutput ( ")" ) ;
emitter . emitJavascriptStatements ( this . body , true , false ) ;
emitter . setInObjectLiteral ( temp ) ;
emitter . recordSourceMappingEnd ( this ) ;
emitter . emitParensAndCommentsInPlace ( this , false ) ;
}
public typeCheck ( typeFlow : TypeFlow ) {
return typeFlow . typeCheckFor ( this ) ;
}
public addToControlFlow ( context : ControlFlowContext ) : void {
if ( this . init ) {
context . addContent ( this . init ) ;
}
var loopHeader = context . current ;
var loopStart = new BasicBlock ( ) ;
var afterLoop = new BasicBlock ( ) ;
loopHeader . addSuccessor ( loopStart ) ;
context . current = loopStart ;
var condBlock : BasicBlock = null ;
var continueTarget = loopStart ;
var incrBB : BasicBlock = null ;
if ( this . incr ) {
incrBB = new BasicBlock ( ) ;
continueTarget = incrBB ;
}
if ( this . cond ) {
condBlock = context . current ;
context . addContent ( this . cond ) ;
context . current = new BasicBlock ( ) ;
condBlock . addSuccessor ( context . current ) ;
}
var targetInfo : ITargetInfo = null ;
if ( this . body ) {
context . pushStatement ( this , continueTarget , afterLoop ) ;
context . walk ( this . body , this ) ;
targetInfo = context . popStatement ( ) ;
}
if ( this . incr ) {
if ( context . noContinuation ) {
if ( incrBB . predecessors . length == 0 ) {
context . addUnreachable ( this . incr ) ;
}
}
else {
context . current . addSuccessor ( incrBB ) ;
context . current = incrBB ;
context . addContent ( this . incr ) ;
}
}
var loopEnd = context . current ;
if ( ! ( context . noContinuation ) ) {
loopEnd . addSuccessor ( loopStart ) ;
}
if ( condBlock ) {
condBlock . addSuccessor ( afterLoop ) ;
context . noContinuation = false ;
}
if ( afterLoop . predecessors . length > 0 ) {
context . noContinuation = false ;
context . current = afterLoop ;
}
context . walker . options . goChildren = false ;
}
}
export class WithStatement extends Statement {
public body : AST ;
public isCompoundStatement ( ) { return true ; }
public withSym : WithSymbol = null ;
constructor ( public expr : AST ) {
super ( NodeType . With ) ;
}
public emit ( emitter : Emitter , tokenId : TokenID , startLine : boolean ) {
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . recordSourceMappingStart ( this ) ;
emitter . writeToOutput ( "with (" ) ;
if ( this . expr ) {
emitter . emitJavascript ( this . expr , TokenID . With , false ) ;
}
emitter . writeToOutput ( ")" ) ;
emitter . emitJavascriptStatements ( this . body , true , false ) ;
emitter . recordSourceMappingEnd ( this ) ;
emitter . emitParensAndCommentsInPlace ( this , false ) ;
}
public typeCheck ( typeFlow : TypeFlow ) {
return typeFlow . typeCheckWith ( this ) ;
}
}
export class SwitchStatement extends Statement {
public caseList : ASTList ;
public defaultCase : CaseStatement = null ;
public statement : ASTSpan = new ASTSpan ( ) ;
constructor ( public val : AST ) {
super ( NodeType . Switch ) ;
}
public isCompoundStatement ( ) { return true ; }
public emit ( emitter : Emitter , tokenId : TokenID , startLine : boolean ) {
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . recordSourceMappingStart ( this ) ;
var temp = emitter . setInObjectLiteral ( false ) ;
emitter . recordSourceMappingStart ( this . statement ) ;
emitter . writeToOutput ( "switch(" ) ;
emitter . emitJavascript ( this . val , TokenID . Identifier , false ) ;
emitter . writeToOutput ( ")" ) ;
emitter . recordSourceMappingEnd ( this . statement ) ;
emitter . writeLineToOutput ( " {" ) ;
emitter . indenter . increaseIndent ( ) ;
var casesLen = this . caseList . members . length ;
for ( var i = 0 ; i < casesLen ; i ++ ) {
var caseExpr = this . caseList . members [ i ] ;
emitter . emitJavascript ( caseExpr , TokenID . Case , true ) ;
emitter . writeLineToOutput ( "" ) ;
}
emitter . indenter . decreaseIndent ( ) ;
emitter . emitIndent ( ) ;
emitter . writeToOutput ( "}" ) ;
emitter . setInObjectLiteral ( temp ) ;
emitter . recordSourceMappingEnd ( this ) ;
emitter . emitParensAndCommentsInPlace ( this , false ) ;
}
public typeCheck ( typeFlow : TypeFlow ) {
var len = this . caseList . members . length ;
this . val = typeFlow . typeCheck ( this . val ) ;
for ( var i = 0 ; i < len ; i ++ ) {
this . caseList . members [ i ] = typeFlow . typeCheck ( this . caseList . members [ i ] ) ;
}
this . defaultCase = < CaseStatement > typeFlow . typeCheck ( this . defaultCase ) ;
this . type = typeFlow . voidType ;
return this ;
}
// if there are break statements that match this switch, then just link cond block with block after switch
public addToControlFlow ( context : ControlFlowContext ) {
var condBlock = context . current ;
context . addContent ( this . val ) ;
var execBlock = new BasicBlock ( ) ;
var afterSwitch = new BasicBlock ( ) ;
condBlock . addSuccessor ( execBlock ) ;
context . pushSwitch ( execBlock ) ;
context . current = execBlock ;
context . pushStatement ( this , execBlock , afterSwitch ) ;
context . walk ( this . caseList , this ) ;
context . popSwitch ( ) ;
var targetInfo = context . popStatement ( ) ;
var hasCondContinuation = ( this . defaultCase == null ) ;
if ( this . defaultCase == null ) {
condBlock . addSuccessor ( afterSwitch ) ;
}
if ( afterSwitch . predecessors . length > 0 ) {
context . noContinuation = false ;
context . current = afterSwitch ;
}
else {
context . noContinuation = true ;
}
context . walker . options . goChildren = false ;
}
}
export class CaseStatement extends Statement {
public expr : AST = null ;
public body : ASTList ;
constructor ( ) {
super ( NodeType . Case ) ;
}
public emit ( emitter : Emitter , tokenId : TokenID , startLine : boolean ) {
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . recordSourceMappingStart ( this ) ;
if ( this . expr ) {
emitter . writeToOutput ( "case " ) ;
emitter . emitJavascript ( this . expr , TokenID . Identifier , false ) ;
}
else {
emitter . writeToOutput ( "default" ) ;
}
emitter . writeToOutput ( ":" ) ;
emitter . emitJavascriptStatements ( this . body , false , false ) ;
emitter . recordSourceMappingEnd ( this ) ;
emitter . emitParensAndCommentsInPlace ( this , false ) ;
}
public typeCheck ( typeFlow : TypeFlow ) {
this . expr = typeFlow . typeCheck ( this . expr ) ;
typeFlow . typeCheck ( this . body ) ;
this . type = typeFlow . voidType ;
return this ;
}
// TODO: more reasoning about unreachable cases (such as duplicate literals as case expressions)
// for now, assume all cases are reachable, regardless of whether some cases fall through
public addToControlFlow ( context : ControlFlowContext ) {
var execBlock = new BasicBlock ( ) ;
var sw = context . currentSwitch [ context . currentSwitch . length - 1 ] ;
// TODO: fall-through from previous (+ to end of switch)
if ( this . expr ) {
var exprBlock = new BasicBlock ( ) ;
context . current = exprBlock ;
sw . addSuccessor ( exprBlock ) ;
context . addContent ( this . expr ) ;
exprBlock . addSuccessor ( execBlock ) ;
}
else {
sw . addSuccessor ( execBlock ) ;
}
context . current = execBlock ;
if ( this . body ) {
context . walk ( this . body , this ) ;
}
context . noContinuation = false ;
context . walker . options . goChildren = false ;
}
}
export class TypeReference extends AST {
constructor ( public term : AST , public arrayCount : number ) {
super ( NodeType . TypeRef ) ;
}
public emit ( emitter : Emitter , tokenId : TokenID , startLine : boolean ) {
throw new Error ( "should not emit a type ref" ) ;
}
public typeCheck ( typeFlow : TypeFlow ) {
var prevInTCTR = typeFlow . inTypeRefTypeCheck ;
typeFlow . inTypeRefTypeCheck = true ;
var typeLink = getTypeLink ( this , typeFlow . checker , true ) ;
typeFlow . checker . resolveTypeLink ( typeFlow . scope , typeLink , false ) ;
if ( this . term ) {
typeFlow . typeCheck ( this . term ) ;
}
typeFlow . checkForVoidConstructor ( typeLink . type , this ) ;
this . type = typeLink . type ;
// in error recovery cases, there may not be a term
if ( this . term ) {
this . term . type = this . type ;
}
typeFlow . inTypeRefTypeCheck = prevInTCTR ;
return this ;
}
}
export class TryFinally extends Statement {
constructor ( public tryNode : AST , public finallyNode : Finally ) {
super ( NodeType . TryFinally ) ;
}
public isCompoundStatement ( ) { return true ; }
public emit ( emitter : Emitter , tokenId : TokenID , startLine : boolean ) {
emitter . recordSourceMappingStart ( this ) ;
emitter . emitJavascript ( this . tryNode , TokenID . Try , false ) ;
emitter . emitJavascript ( this . finallyNode , TokenID . Finally , false ) ;
emitter . recordSourceMappingEnd ( this ) ;
}
public typeCheck ( typeFlow : TypeFlow ) {
this . tryNode = typeFlow . typeCheck ( this . tryNode ) ;
this . finallyNode = < Finally > typeFlow . typeCheck ( this . finallyNode ) ;
this . type = typeFlow . voidType ;
return this ;
}
public addToControlFlow ( context : ControlFlowContext ) {
var afterFinally = new BasicBlock ( ) ;
context . walk ( this . tryNode , this ) ;
var finBlock = new BasicBlock ( ) ;
if ( context . current ) {
context . current . addSuccessor ( finBlock ) ;
}
context . current = finBlock ;
context . pushStatement ( this , null , afterFinally ) ;
context . walk ( this . finallyNode , this ) ;
if ( ! context . noContinuation && context . current ) {
context . current . addSuccessor ( afterFinally ) ;
}
if ( afterFinally . predecessors . length > 0 ) {
context . current = afterFinally ;
}
else {
context . noContinuation = true ;
}
context . popStatement ( ) ;
context . walker . options . goChildren = false ;
}
}
export class TryCatch extends Statement {
constructor ( public tryNode : Try , public catchNode : Catch ) {
super ( NodeType . TryCatch ) ;
}
public isCompoundStatement ( ) { return true ; }
public emit ( emitter : Emitter , tokenId : TokenID , startLine : boolean ) {
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . recordSourceMappingStart ( this ) ;
emitter . emitJavascript ( this . tryNode , TokenID . Try , false ) ;
emitter . emitJavascript ( this . catchNode , TokenID . Catch , false ) ;
emitter . recordSourceMappingEnd ( this ) ;
emitter . emitParensAndCommentsInPlace ( this , false ) ;
}
public addToControlFlow ( context : ControlFlowContext ) {
var beforeTry = context . current ;
var tryBlock = new BasicBlock ( ) ;
beforeTry . addSuccessor ( tryBlock ) ;
context . current = tryBlock ;
var afterTryCatch = new BasicBlock ( ) ;
context . pushStatement ( this , null , afterTryCatch ) ;
context . walk ( this . tryNode , this ) ;
if ( ! context . noContinuation ) {
if ( context . current ) {
context . current . addSuccessor ( afterTryCatch ) ;
}
}
context . current = new BasicBlock ( ) ;
beforeTry . addSuccessor ( context . current ) ;
context . walk ( this . catchNode , this ) ;
context . popStatement ( ) ;
if ( ! context . noContinuation ) {
if ( context . current ) {
context . current . addSuccessor ( afterTryCatch ) ;
}
}
context . current = afterTryCatch ;
context . walker . options . goChildren = false ;
}
public typeCheck ( typeFlow : TypeFlow ) {
this . tryNode = < Try > typeFlow . typeCheck ( this . tryNode ) ;
this . catchNode = < Catch > typeFlow . typeCheck ( this . catchNode ) ;
this . type = typeFlow . voidType ;
return this ;
}
}
export class Try extends Statement {
constructor ( public body : AST ) {
super ( NodeType . Try ) ;
}
public emit ( emitter : Emitter , tokenId : TokenID , startLine : boolean ) {
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . recordSourceMappingStart ( this ) ;
emitter . writeToOutput ( "try " ) ;
emitter . emitJavascript ( this . body , TokenID . Try , false ) ;
emitter . recordSourceMappingEnd ( this ) ;
emitter . emitParensAndCommentsInPlace ( this , false ) ;
}
public typeCheck ( typeFlow : TypeFlow ) {
this . body = typeFlow . typeCheck ( this . body ) ;
return this ;
}
public addToControlFlow ( context : ControlFlowContext ) {
if ( this . body ) {
context . walk ( this . body , this ) ;
}
context . walker . options . goChildren = false ;
context . noContinuation = false ;
}
}
export class Catch extends Statement {
constructor ( public param : VarDecl , public body : AST ) {
super ( NodeType . Catch ) ;
if ( this . param ) {
this . param . varFlags |= VarFlags . AutoInit ;
}
}
public statement : ASTSpan = new ASTSpan ( ) ;
public containedScope : SymbolScope = null ;
public emit ( emitter : Emitter , tokenId : TokenID , startLine : boolean ) {
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . recordSourceMappingStart ( this ) ;
emitter . writeToOutput ( " " ) ;
emitter . recordSourceMappingStart ( this . statement ) ;
emitter . writeToOutput ( "catch (" ) ;
emitter . emitJavascript ( this . param , TokenID . OpenParen , false ) ;
emitter . writeToOutput ( ")" ) ;
emitter . recordSourceMappingEnd ( this . statement ) ;
emitter . emitJavascript ( this . body , TokenID . Catch , false ) ;
emitter . recordSourceMappingEnd ( this ) ;
emitter . emitParensAndCommentsInPlace ( this , false ) ;
}
public addToControlFlow ( context : ControlFlowContext ) {
if ( this . param ) {
context . addContent ( this . param ) ;
var bodBlock = new BasicBlock ( ) ;
context . current . addSuccessor ( bodBlock ) ;
context . current = bodBlock ;
}
if ( this . body ) {
context . walk ( this . body , this ) ;
}
context . noContinuation = false ;
context . walker . options . goChildren = false ;
}
public typeCheck ( typeFlow : TypeFlow ) {
var prevScope = typeFlow . scope ;
typeFlow . scope = this . containedScope ;
this . param = < VarDecl > typeFlow . typeCheck ( this . param ) ;
var exceptVar = new ValueLocation ( ) ;
var varSym = new VariableSymbol ( ( < VarDecl > this . param ) . id . text ,
this . param . minChar ,
typeFlow . checker . locationInfo . unitIndex ,
exceptVar ) ;
exceptVar . symbol = varSym ;
exceptVar . typeLink = new TypeLink ( ) ;
// var type for now (add syntax for type annotation)
exceptVar . typeLink . type = typeFlow . anyType ;
var thisFnc = typeFlow . thisFnc ;
if ( thisFnc && thisFnc . type ) {
exceptVar . symbol . container = thisFnc . type . symbol ;
}
else {
exceptVar . symbol . container = null ;
}
this . param . sym = exceptVar . symbol ;
typeFlow . scope . enter ( exceptVar . symbol . container , this . param , exceptVar . symbol ,
typeFlow . checker . errorReporter , false , false , false ) ;
this . body = typeFlow . typeCheck ( this . body ) ;
// if we're in provisional typecheck mode, clean up the symbol entry
// REVIEW: This is obviously bad form, since we're counting on the internal
// layout of the symbol table, but this is also the only place where we insert
// symbols during typecheck
if ( typeFlow . checker . inProvisionalTypecheckMode ( ) ) {
var table = typeFlow . scope . getTable ( ) ;
( < any > table ) . secondaryTable . table [ exceptVar . symbol . name ] = undefined ;
}
this . type = typeFlow . voidType ;
typeFlow . scope = prevScope ;
return this ;
}
}
export class Finally extends Statement {
constructor ( public body : AST ) {
super ( NodeType . Finally ) ;
}
public emit ( emitter : Emitter , tokenId : TokenID , startLine : boolean ) {
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . recordSourceMappingStart ( this ) ;
emitter . writeToOutput ( "finally" ) ;
emitter . emitJavascript ( this . body , TokenID . Finally , false ) ;
emitter . recordSourceMappingEnd ( this ) ;
emitter . emitParensAndCommentsInPlace ( this , false ) ;
}
public addToControlFlow ( context : ControlFlowContext ) {
if ( this . body ) {
context . walk ( this . body , this ) ;
}
context . walker . options . goChildren = false ;
context . noContinuation = false ;
}
public typeCheck ( typeFlow : TypeFlow ) {
this . body = typeFlow . typeCheck ( this . body ) ;
return this ;
}
}
export class Comment extends AST {
public text : string [ ] = null ;
constructor ( public content : string , public isBlockComment : boolean , public endsLine ) {
super ( NodeType . Comment ) ;
}
public getText ( ) : string [ ] {
if ( this . text == null ) {
if ( this . isBlockComment ) {
this . text = this . content . split ( "\n" ) ;
for ( var i = 0 ; i < this . text . length ; i ++ ) {
this . text [ i ] = this . text [ i ] . replace ( /^\s+|\s+$/g , '' ) ;
}
}
else {
this . text = [ ( this . content . replace ( /^\s+|\s+$/g , '' ) ) ] ;
}
}
return this . text ;
}
}
export class DebuggerStatement extends Statement {
constructor ( ) {
super ( NodeType . Debugger ) ;
}
public emit ( emitter : Emitter , tokenId : TokenID , startLine : boolean ) {
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . recordSourceMappingStart ( this ) ;
emitter . writeLineToOutput ( "debugger;" ) ;
emitter . recordSourceMappingEnd ( this ) ;
emitter . emitParensAndCommentsInPlace ( this , false ) ;
}
}
}
//// [parserRealSource11.js]
// Copyright (c) Microsoft. All rights reserved. Licensed under the Apache License, Version 2.0.
// See LICENSE.txt in the project root for complete license information.
var _ _extends = this . _ _extends || function ( d , b ) {
for ( var p in b ) if ( b . hasOwnProperty ( p ) ) d [ p ] = b [ p ] ;
function _ _ ( ) { this . constructor = d ; }
_ _ . prototype = b . prototype ;
d . prototype = new _ _ ( ) ;
} ;
///<reference path='typescript.ts' />
var TypeScript ;
( function ( TypeScript ) {
var ASTSpan = ( function ( ) {
function ASTSpan ( ) {
this . minChar = - 1 ; // -1 = "undefined" or "compiler generated"
this . limChar = - 1 ; // -1 = "undefined" or "compiler generated"
}
return ASTSpan ;
} ) ( ) ;
TypeScript . ASTSpan = ASTSpan ;
var AST = ( function ( _super ) {
_ _extends ( AST , _super ) ;
function AST ( nodeType ) {
_super . call ( this ) ;
this . nodeType = nodeType ;
this . type = null ;
this . flags = ASTFlags . Writeable ;
// REVIEW: for diagnostic purposes
this . passCreated = CompilerDiagnostics . analysisPass ;
this . preComments = null ;
this . postComments = null ;
this . isParenthesized = false ;
}
2015-02-07 05:03:24 +01:00
AST . prototype . isExpression = function ( ) { return false ; } ;
AST . prototype . isStatementOrExpression = function ( ) { return false ; } ;
AST . prototype . isCompoundStatement = function ( ) { return false ; } ;
AST . prototype . isLeaf = function ( ) { return this . isStatementOrExpression ( ) && ( ! this . isCompoundStatement ( ) ) ; } ;
2015-02-03 00:30:33 +01:00
AST . prototype . typeCheck = function ( typeFlow ) {
switch ( this . nodeType ) {
case NodeType . Error :
case NodeType . EmptyExpr :
this . type = typeFlow . anyType ;
break ;
case NodeType . This :
return typeFlow . typeCheckThis ( this ) ;
case NodeType . Null :
this . type = typeFlow . nullType ;
break ;
case NodeType . False :
case NodeType . True :
this . type = typeFlow . booleanType ;
break ;
case NodeType . Super :
return typeFlow . typeCheckSuper ( this ) ;
case NodeType . EndCode :
case NodeType . Empty :
case NodeType . Void :
this . type = typeFlow . voidType ;
break ;
default :
throw new Error ( "please implement in derived class" ) ;
}
return this ;
} ;
AST . prototype . emit = function ( emitter , tokenId , startLine ) {
emitter . emitParensAndCommentsInPlace ( this , true ) ;
switch ( this . nodeType ) {
case NodeType . This :
emitter . recordSourceMappingStart ( this ) ;
if ( emitter . thisFnc && ( hasFlag ( emitter . thisFnc . fncFlags , FncFlags . IsFatArrowFunction ) ) ) {
emitter . writeToOutput ( "_this" ) ;
}
else {
emitter . writeToOutput ( "this" ) ;
}
emitter . recordSourceMappingEnd ( this ) ;
break ;
case NodeType . Null :
emitter . recordSourceMappingStart ( this ) ;
emitter . writeToOutput ( "null" ) ;
emitter . recordSourceMappingEnd ( this ) ;
break ;
case NodeType . False :
emitter . recordSourceMappingStart ( this ) ;
emitter . writeToOutput ( "false" ) ;
emitter . recordSourceMappingEnd ( this ) ;
break ;
case NodeType . True :
emitter . recordSourceMappingStart ( this ) ;
emitter . writeToOutput ( "true" ) ;
emitter . recordSourceMappingEnd ( this ) ;
break ;
case NodeType . Super :
emitter . recordSourceMappingStart ( this ) ;
emitter . emitSuperReference ( ) ;
emitter . recordSourceMappingEnd ( this ) ;
break ;
case NodeType . EndCode :
break ;
case NodeType . Error :
case NodeType . EmptyExpr :
break ;
case NodeType . Empty :
emitter . recordSourceMappingStart ( this ) ;
emitter . writeToOutput ( "; " ) ;
emitter . recordSourceMappingEnd ( this ) ;
break ;
case NodeType . Void :
emitter . recordSourceMappingStart ( this ) ;
emitter . writeToOutput ( "void " ) ;
emitter . recordSourceMappingEnd ( this ) ;
break ;
default :
throw new Error ( "please implement in derived class" ) ;
}
emitter . emitParensAndCommentsInPlace ( this , false ) ;
} ;
AST . prototype . print = function ( context ) {
context . startLine ( ) ;
var lineCol = { line : - 1 , col : - 1 } ;
var limLineCol = { line : - 1 , col : - 1 } ;
if ( context . parser !== null ) {
context . parser . getSourceLineCol ( lineCol , this . minChar ) ;
context . parser . getSourceLineCol ( limLineCol , this . limChar ) ;
2015-02-21 06:53:44 +01:00
context . write ( "(" + lineCol . line + "," + lineCol . col + ")--" +
"(" + limLineCol . line + "," + limLineCol . col + "): " ) ;
2015-02-03 00:30:33 +01:00
}
var lab = this . printLabel ( ) ;
if ( hasFlag ( this . flags , ASTFlags . Error ) ) {
lab += " (Error)" ;
}
context . writeLine ( lab ) ;
} ;
AST . prototype . printLabel = function ( ) {
if ( nodeTypeTable [ this . nodeType ] !== undefined ) {
return nodeTypeTable [ this . nodeType ] ;
}
else {
return NodeType . _map [ this . nodeType ] ;
}
} ;
AST . prototype . addToControlFlow = function ( context ) {
// by default, AST adds itself to current basic block and does not check its children
context . walker . options . goChildren = false ;
context . addContent ( this ) ;
} ;
AST . prototype . netFreeUses = function ( container , freeUses ) {
} ;
AST . prototype . treeViewLabel = function ( ) {
return NodeType . _map [ this . nodeType ] ;
} ;
AST . getResolvedIdentifierName = function ( name ) {
if ( ! name )
return "" ;
var resolved = "" ;
var start = 0 ;
var i = 0 ;
while ( i <= name . length - 6 ) {
// Look for escape sequence \uxxxx
if ( name . charAt ( i ) == '\\' && name . charAt ( i + 1 ) == 'u' ) {
var charCode = parseInt ( name . substr ( i + 2 , 4 ) , 16 ) ;
resolved += name . substr ( start , i - start ) ;
resolved += String . fromCharCode ( charCode ) ;
i += 6 ;
start = i ;
continue ;
}
i ++ ;
}
// Append remaining string
resolved += name . substring ( start ) ;
return resolved ;
} ;
return AST ;
} ) ( ASTSpan ) ;
TypeScript . AST = AST ;
var IncompleteAST = ( function ( _super ) {
_ _extends ( IncompleteAST , _super ) ;
function IncompleteAST ( min , lim ) {
_super . call ( this , NodeType . Error ) ;
this . minChar = min ;
this . limChar = lim ;
}
return IncompleteAST ;
} ) ( AST ) ;
TypeScript . IncompleteAST = IncompleteAST ;
var ASTList = ( function ( _super ) {
_ _extends ( ASTList , _super ) ;
function ASTList ( ) {
_super . call ( this , NodeType . List ) ;
this . enclosingScope = null ;
this . members = new AST [ ] ;
}
ASTList . prototype . addToControlFlow = function ( context ) {
var len = this . members . length ;
for ( var i = 0 ; i < len ; i ++ ) {
if ( context . noContinuation ) {
context . addUnreachable ( this . members [ i ] ) ;
break ;
}
else {
this . members [ i ] = context . walk ( this . members [ i ] , this ) ;
}
}
context . walker . options . goChildren = false ;
} ;
ASTList . prototype . append = function ( ast ) {
this . members [ this . members . length ] = ast ;
return this ;
} ;
ASTList . prototype . appendAll = function ( ast ) {
if ( ast . nodeType == NodeType . List ) {
var list = ast ;
for ( var i = 0 , len = list . members . length ; i < len ; i ++ ) {
this . append ( list . members [ i ] ) ;
}
}
else {
this . append ( ast ) ;
}
return this ;
} ;
ASTList . prototype . emit = function ( emitter , tokenId , startLine ) {
emitter . recordSourceMappingStart ( this ) ;
emitter . emitJavascriptList ( this , null , TokenID . Semicolon , startLine , false , false ) ;
emitter . recordSourceMappingEnd ( this ) ;
} ;
ASTList . prototype . typeCheck = function ( typeFlow ) {
var len = this . members . length ;
typeFlow . nestingLevel ++ ;
for ( var i = 0 ; i < len ; i ++ ) {
if ( this . members [ i ] ) {
this . members [ i ] = this . members [ i ] . typeCheck ( typeFlow ) ;
}
}
typeFlow . nestingLevel -- ;
return this ;
} ;
return ASTList ;
} ) ( AST ) ;
TypeScript . ASTList = ASTList ;
var Identifier = ( function ( _super ) {
_ _extends ( Identifier , _super ) ;
// 'actualText' is the text that the user has entered for the identifier. the text might
// include any Unicode escape sequences (e.g.: \u0041 for 'A'). 'text', however, contains
// the resolved value of any escape sequences in the actual text; so in the previous
// example, actualText = '\u0041', text = 'A'.
//
// For purposes of finding a symbol, use text, as this will allow you to match all
// variations of the variable text. For full-fidelity translation of the user input, such
// as emitting, use the actualText field.
//
// Note:
// To change text, and to avoid running into a situation where 'actualText' does not
// match 'text', always use setText.
function Identifier ( actualText , hasEscapeSequence ) {
_super . call ( this , NodeType . Name ) ;
this . actualText = actualText ;
this . hasEscapeSequence = hasEscapeSequence ;
this . sym = null ;
this . cloId = - 1 ;
this . setText ( actualText , hasEscapeSequence ) ;
}
Identifier . prototype . setText = function ( actualText , hasEscapeSequence ) {
this . actualText = actualText ;
if ( hasEscapeSequence ) {
this . text = AST . getResolvedIdentifierName ( actualText ) ;
}
else {
this . text = actualText ;
}
} ;
2015-02-07 05:03:24 +01:00
Identifier . prototype . isMissing = function ( ) { return false ; } ;
Identifier . prototype . isLeaf = function ( ) { return true ; } ;
2015-02-03 00:30:33 +01:00
Identifier . prototype . treeViewLabel = function ( ) {
return "id: " + this . actualText ;
} ;
Identifier . prototype . printLabel = function ( ) {
if ( this . actualText ) {
return "id: " + this . actualText ;
}
else {
return "name node" ;
}
} ;
Identifier . prototype . typeCheck = function ( typeFlow ) {
return typeFlow . typeCheckName ( this ) ;
} ;
Identifier . prototype . emit = function ( emitter , tokenId , startLine ) {
emitter . emitJavascriptName ( this , true ) ;
} ;
Identifier . fromToken = function ( token ) {
return new Identifier ( token . getText ( ) , token . hasEscapeSequence ) ;
} ;
return Identifier ;
} ) ( AST ) ;
TypeScript . Identifier = Identifier ;
var MissingIdentifier = ( function ( _super ) {
_ _extends ( MissingIdentifier , _super ) ;
function MissingIdentifier ( ) {
_super . call ( this , "__missing" ) ;
}
MissingIdentifier . prototype . isMissing = function ( ) {
return true ;
} ;
MissingIdentifier . prototype . emit = function ( emitter , tokenId , startLine ) {
// Emit nothing for a missing ID
} ;
return MissingIdentifier ;
} ) ( Identifier ) ;
TypeScript . MissingIdentifier = MissingIdentifier ;
var Label = ( function ( _super ) {
_ _extends ( Label , _super ) ;
function Label ( id ) {
_super . call ( this , NodeType . Label ) ;
this . id = id ;
}
2015-02-07 05:03:24 +01:00
Label . prototype . printLabel = function ( ) { return this . id . actualText + ":" ; } ;
2015-02-03 00:30:33 +01:00
Label . prototype . typeCheck = function ( typeFlow ) {
this . type = typeFlow . voidType ;
return this ;
} ;
Label . prototype . emit = function ( emitter , tokenId , startLine ) {
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . recordSourceMappingStart ( this ) ;
emitter . recordSourceMappingStart ( this . id ) ;
emitter . writeToOutput ( this . id . actualText ) ;
emitter . recordSourceMappingEnd ( this . id ) ;
emitter . writeLineToOutput ( ":" ) ;
emitter . recordSourceMappingEnd ( this ) ;
emitter . emitParensAndCommentsInPlace ( this , false ) ;
} ;
return Label ;
} ) ( AST ) ;
TypeScript . Label = Label ;
var Expression = ( function ( _super ) {
_ _extends ( Expression , _super ) ;
function Expression ( nodeType ) {
_super . call ( this , nodeType ) ;
}
2015-02-07 05:03:24 +01:00
Expression . prototype . isExpression = function ( ) { return true ; } ;
Expression . prototype . isStatementOrExpression = function ( ) { return true ; } ;
2015-02-03 00:30:33 +01:00
return Expression ;
} ) ( AST ) ;
TypeScript . Expression = Expression ;
var UnaryExpression = ( function ( _super ) {
_ _extends ( UnaryExpression , _super ) ;
function UnaryExpression ( nodeType , operand ) {
_super . call ( this , nodeType ) ;
this . operand = operand ;
this . targetType = null ; // Target type for an object literal (null if no target type)
this . castTerm = null ;
}
UnaryExpression . prototype . addToControlFlow = function ( context ) {
_super . prototype . addToControlFlow . call ( this , context ) ;
// TODO: add successor as catch block/finally block if present
if ( this . nodeType == NodeType . Throw ) {
context . returnStmt ( ) ;
}
} ;
UnaryExpression . prototype . typeCheck = function ( typeFlow ) {
switch ( this . nodeType ) {
case NodeType . Not :
return typeFlow . typeCheckBitNot ( this ) ;
case NodeType . LogNot :
return typeFlow . typeCheckLogNot ( this ) ;
case NodeType . Pos :
case NodeType . Neg :
return typeFlow . typeCheckUnaryNumberOperator ( this ) ;
case NodeType . IncPost :
case NodeType . IncPre :
case NodeType . DecPost :
case NodeType . DecPre :
return typeFlow . typeCheckIncOrDec ( this ) ;
case NodeType . ArrayLit :
typeFlow . typeCheckArrayLit ( this ) ;
return this ;
case NodeType . ObjectLit :
typeFlow . typeCheckObjectLit ( this ) ;
return this ;
case NodeType . Throw :
this . operand = typeFlow . typeCheck ( this . operand ) ;
this . type = typeFlow . voidType ;
return this ;
case NodeType . Typeof :
this . operand = typeFlow . typeCheck ( this . operand ) ;
this . type = typeFlow . stringType ;
return this ;
case NodeType . Delete :
this . operand = typeFlow . typeCheck ( this . operand ) ;
this . type = typeFlow . booleanType ;
break ;
case NodeType . TypeAssertion :
this . castTerm = typeFlow . typeCheck ( this . castTerm ) ;
var applyTargetType = ! this . operand . isParenthesized ;
var targetType = applyTargetType ? this . castTerm . type : null ;
typeFlow . checker . typeCheckWithContextualType ( targetType , typeFlow . checker . inProvisionalTypecheckMode ( ) , true , this . operand ) ;
typeFlow . castWithCoercion ( this . operand , this . castTerm . type , false , true ) ;
this . type = this . castTerm . type ;
return this ;
case NodeType . Void :
// REVIEW - Although this is good to do for completeness's sake,
// this shouldn't be strictly necessary from the void operator's
// point of view
this . operand = typeFlow . typeCheck ( this . operand ) ;
this . type = typeFlow . checker . undefinedType ;
break ;
default :
throw new Error ( "please implement in derived class" ) ;
}
return this ;
} ;
UnaryExpression . prototype . emit = function ( emitter , tokenId , startLine ) {
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . recordSourceMappingStart ( this ) ;
switch ( this . nodeType ) {
case NodeType . IncPost :
emitter . emitJavascript ( this . operand , TokenID . PlusPlus , false ) ;
emitter . writeToOutput ( "++" ) ;
break ;
case NodeType . LogNot :
emitter . writeToOutput ( "!" ) ;
emitter . emitJavascript ( this . operand , TokenID . Exclamation , false ) ;
break ;
case NodeType . DecPost :
emitter . emitJavascript ( this . operand , TokenID . MinusMinus , false ) ;
emitter . writeToOutput ( "--" ) ;
break ;
case NodeType . ObjectLit :
emitter . emitObjectLiteral ( this . operand ) ;
break ;
case NodeType . ArrayLit :
emitter . emitArrayLiteral ( this . operand ) ;
break ;
case NodeType . Not :
emitter . writeToOutput ( "~" ) ;
emitter . emitJavascript ( this . operand , TokenID . Tilde , false ) ;
break ;
case NodeType . Neg :
emitter . writeToOutput ( "-" ) ;
if ( this . operand . nodeType == NodeType . Neg ) {
this . operand . isParenthesized = true ;
}
emitter . emitJavascript ( this . operand , TokenID . Minus , false ) ;
break ;
case NodeType . Pos :
emitter . writeToOutput ( "+" ) ;
if ( this . operand . nodeType == NodeType . Pos ) {
this . operand . isParenthesized = true ;
}
emitter . emitJavascript ( this . operand , TokenID . Plus , false ) ;
break ;
case NodeType . IncPre :
emitter . writeToOutput ( "++" ) ;
emitter . emitJavascript ( this . operand , TokenID . PlusPlus , false ) ;
break ;
case NodeType . DecPre :
emitter . writeToOutput ( "--" ) ;
emitter . emitJavascript ( this . operand , TokenID . MinusMinus , false ) ;
break ;
case NodeType . Throw :
emitter . writeToOutput ( "throw " ) ;
emitter . emitJavascript ( this . operand , TokenID . Tilde , false ) ;
emitter . writeToOutput ( ";" ) ;
break ;
case NodeType . Typeof :
emitter . writeToOutput ( "typeof " ) ;
emitter . emitJavascript ( this . operand , TokenID . Tilde , false ) ;
break ;
case NodeType . Delete :
emitter . writeToOutput ( "delete " ) ;
emitter . emitJavascript ( this . operand , TokenID . Tilde , false ) ;
break ;
case NodeType . Void :
emitter . writeToOutput ( "void " ) ;
emitter . emitJavascript ( this . operand , TokenID . Tilde , false ) ;
break ;
case NodeType . TypeAssertion :
emitter . emitJavascript ( this . operand , TokenID . Tilde , false ) ;
break ;
default :
throw new Error ( "please implement in derived class" ) ;
}
emitter . recordSourceMappingEnd ( this ) ;
emitter . emitParensAndCommentsInPlace ( this , false ) ;
} ;
return UnaryExpression ;
} ) ( Expression ) ;
TypeScript . UnaryExpression = UnaryExpression ;
var CallExpression = ( function ( _super ) {
_ _extends ( CallExpression , _super ) ;
function CallExpression ( nodeType , target , arguments ) {
_super . call ( this , nodeType ) ;
this . target = target ;
this . arguments = arguments ;
this . signature = null ;
this . minChar = this . target . minChar ;
}
CallExpression . prototype . typeCheck = function ( typeFlow ) {
if ( this . nodeType == NodeType . New ) {
return typeFlow . typeCheckNew ( this ) ;
}
else {
return typeFlow . typeCheckCall ( this ) ;
}
} ;
CallExpression . prototype . emit = function ( emitter , tokenId , startLine ) {
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . recordSourceMappingStart ( this ) ;
if ( this . nodeType == NodeType . New ) {
emitter . emitNew ( this . target , this . arguments ) ;
}
else {
emitter . emitCall ( this , this . target , this . arguments ) ;
}
emitter . recordSourceMappingEnd ( this ) ;
emitter . emitParensAndCommentsInPlace ( this , false ) ;
} ;
return CallExpression ;
} ) ( Expression ) ;
TypeScript . CallExpression = CallExpression ;
var BinaryExpression = ( function ( _super ) {
_ _extends ( BinaryExpression , _super ) ;
function BinaryExpression ( nodeType , operand1 , operand2 ) {
_super . call ( this , nodeType ) ;
this . operand1 = operand1 ;
this . operand2 = operand2 ;
}
BinaryExpression . prototype . typeCheck = function ( typeFlow ) {
switch ( this . nodeType ) {
case NodeType . Dot :
return typeFlow . typeCheckDotOperator ( this ) ;
case NodeType . Asg :
return typeFlow . typeCheckAsgOperator ( this ) ;
case NodeType . Add :
case NodeType . Sub :
case NodeType . Mul :
case NodeType . Div :
case NodeType . Mod :
case NodeType . Or :
case NodeType . And :
return typeFlow . typeCheckArithmeticOperator ( this , false ) ;
case NodeType . Xor :
return typeFlow . typeCheckBitwiseOperator ( this , false ) ;
case NodeType . Ne :
case NodeType . Eq :
var text ;
if ( typeFlow . checker . styleSettings . eqeqeq ) {
text = nodeTypeTable [ this . nodeType ] ;
typeFlow . checker . errorReporter . styleError ( this , "use of " + text ) ;
}
else if ( typeFlow . checker . styleSettings . eqnull ) {
text = nodeTypeTable [ this . nodeType ] ;
if ( ( this . operand2 !== null ) && ( this . operand2 . nodeType == NodeType . Null ) ) {
typeFlow . checker . errorReporter . styleError ( this , "use of " + text + " to compare with null" ) ;
}
}
case NodeType . Eqv :
case NodeType . NEqv :
case NodeType . Lt :
case NodeType . Le :
case NodeType . Ge :
case NodeType . Gt :
return typeFlow . typeCheckBooleanOperator ( this ) ;
case NodeType . Index :
return typeFlow . typeCheckIndex ( this ) ;
case NodeType . Member :
this . type = typeFlow . voidType ;
return this ;
case NodeType . LogOr :
return typeFlow . typeCheckLogOr ( this ) ;
case NodeType . LogAnd :
return typeFlow . typeCheckLogAnd ( this ) ;
case NodeType . AsgAdd :
case NodeType . AsgSub :
case NodeType . AsgMul :
case NodeType . AsgDiv :
case NodeType . AsgMod :
case NodeType . AsgOr :
case NodeType . AsgAnd :
return typeFlow . typeCheckArithmeticOperator ( this , true ) ;
case NodeType . AsgXor :
return typeFlow . typeCheckBitwiseOperator ( this , true ) ;
case NodeType . Lsh :
case NodeType . Rsh :
case NodeType . Rs2 :
return typeFlow . typeCheckShift ( this , false ) ;
case NodeType . AsgLsh :
case NodeType . AsgRsh :
case NodeType . AsgRs2 :
return typeFlow . typeCheckShift ( this , true ) ;
case NodeType . Comma :
return typeFlow . typeCheckCommaOperator ( this ) ;
case NodeType . InstOf :
return typeFlow . typeCheckInstOf ( this ) ;
case NodeType . In :
return typeFlow . typeCheckInOperator ( this ) ;
case NodeType . From :
typeFlow . checker . errorReporter . simpleError ( this , "Illegal use of 'from' keyword in binary expression" ) ;
break ;
default :
throw new Error ( "please implement in derived class" ) ;
}
return this ;
} ;
BinaryExpression . prototype . emit = function ( emitter , tokenId , startLine ) {
var binTokenId = nodeTypeToTokTable [ this . nodeType ] ;
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . recordSourceMappingStart ( this ) ;
if ( binTokenId != undefined ) {
emitter . emitJavascript ( this . operand1 , binTokenId , false ) ;
if ( tokenTable [ binTokenId ] . text == "instanceof" ) {
emitter . writeToOutput ( " instanceof " ) ;
}
else if ( tokenTable [ binTokenId ] . text == "in" ) {
emitter . writeToOutput ( " in " ) ;
}
else {
emitter . writeToOutputTrimmable ( " " + tokenTable [ binTokenId ] . text + " " ) ;
}
emitter . emitJavascript ( this . operand2 , binTokenId , false ) ;
}
else {
switch ( this . nodeType ) {
case NodeType . Dot :
if ( ! emitter . tryEmitConstant ( this ) ) {
emitter . emitJavascript ( this . operand1 , TokenID . Dot , false ) ;
emitter . writeToOutput ( "." ) ;
emitter . emitJavascriptName ( this . operand2 , false ) ;
}
break ;
case NodeType . Index :
emitter . emitIndex ( this . operand1 , this . operand2 ) ;
break ;
case NodeType . Member :
if ( this . operand2 . nodeType == NodeType . FuncDecl && this . operand2 . isAccessor ( ) ) {
var funcDecl = this . operand2 ;
if ( hasFlag ( funcDecl . fncFlags , FncFlags . GetAccessor ) ) {
emitter . writeToOutput ( "get " ) ;
}
else {
emitter . writeToOutput ( "set " ) ;
}
emitter . emitJavascript ( this . operand1 , TokenID . Colon , false ) ;
}
else {
emitter . emitJavascript ( this . operand1 , TokenID . Colon , false ) ;
emitter . writeToOutputTrimmable ( ": " ) ;
}
emitter . emitJavascript ( this . operand2 , TokenID . Comma , false ) ;
break ;
case NodeType . Comma :
emitter . emitJavascript ( this . operand1 , TokenID . Comma , false ) ;
if ( emitter . emitState . inObjectLiteral ) {
emitter . writeLineToOutput ( ", " ) ;
}
else {
emitter . writeToOutput ( "," ) ;
}
emitter . emitJavascript ( this . operand2 , TokenID . Comma , false ) ;
break ;
case NodeType . Is :
throw new Error ( "should be de-sugared during type check" ) ;
default :
throw new Error ( "please implement in derived class" ) ;
}
}
emitter . recordSourceMappingEnd ( this ) ;
emitter . emitParensAndCommentsInPlace ( this , false ) ;
} ;
return BinaryExpression ;
} ) ( Expression ) ;
TypeScript . BinaryExpression = BinaryExpression ;
var ConditionalExpression = ( function ( _super ) {
_ _extends ( ConditionalExpression , _super ) ;
function ConditionalExpression ( operand1 , operand2 , operand3 ) {
_super . call ( this , NodeType . ConditionalExpression ) ;
this . operand1 = operand1 ;
this . operand2 = operand2 ;
this . operand3 = operand3 ;
}
ConditionalExpression . prototype . typeCheck = function ( typeFlow ) {
return typeFlow . typeCheckQMark ( this ) ;
} ;
ConditionalExpression . prototype . emit = function ( emitter , tokenId , startLine ) {
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . recordSourceMappingStart ( this ) ;
emitter . emitJavascript ( this . operand1 , TokenID . Question , false ) ;
emitter . writeToOutput ( " ? " ) ;
emitter . emitJavascript ( this . operand2 , TokenID . Question , false ) ;
emitter . writeToOutput ( " : " ) ;
emitter . emitJavascript ( this . operand3 , TokenID . Question , false ) ;
emitter . recordSourceMappingEnd ( this ) ;
emitter . emitParensAndCommentsInPlace ( this , false ) ;
} ;
return ConditionalExpression ;
} ) ( Expression ) ;
TypeScript . ConditionalExpression = ConditionalExpression ;
var NumberLiteral = ( function ( _super ) {
_ _extends ( NumberLiteral , _super ) ;
function NumberLiteral ( value , hasEmptyFraction ) {
_super . call ( this , NodeType . NumberLit ) ;
this . value = value ;
this . hasEmptyFraction = hasEmptyFraction ;
this . isNegativeZero = false ;
}
NumberLiteral . prototype . typeCheck = function ( typeFlow ) {
this . type = typeFlow . doubleType ;
return this ;
} ;
NumberLiteral . prototype . treeViewLabel = function ( ) {
return "num: " + this . printLabel ( ) ;
} ;
NumberLiteral . prototype . emit = function ( emitter , tokenId , startLine ) {
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . recordSourceMappingStart ( this ) ;
if ( this . isNegativeZero ) {
emitter . writeToOutput ( "-" ) ;
}
emitter . writeToOutput ( this . value . toString ( ) ) ;
if ( this . hasEmptyFraction )
emitter . writeToOutput ( ".0" ) ;
emitter . recordSourceMappingEnd ( this ) ;
emitter . emitParensAndCommentsInPlace ( this , false ) ;
} ;
NumberLiteral . prototype . printLabel = function ( ) {
if ( Math . floor ( this . value ) != this . value ) {
return this . value . toFixed ( 2 ) . toString ( ) ;
}
else if ( this . hasEmptyFraction ) {
return this . value . toString ( ) + ".0" ;
}
else {
return this . value . toString ( ) ;
}
} ;
return NumberLiteral ;
} ) ( Expression ) ;
TypeScript . NumberLiteral = NumberLiteral ;
var RegexLiteral = ( function ( _super ) {
_ _extends ( RegexLiteral , _super ) ;
function RegexLiteral ( regex ) {
_super . call ( this , NodeType . Regex ) ;
this . regex = regex ;
}
RegexLiteral . prototype . typeCheck = function ( typeFlow ) {
this . type = typeFlow . regexType ;
return this ;
} ;
RegexLiteral . prototype . emit = function ( emitter , tokenId , startLine ) {
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . recordSourceMappingStart ( this ) ;
emitter . writeToOutput ( this . regex . toString ( ) ) ;
emitter . recordSourceMappingEnd ( this ) ;
emitter . emitParensAndCommentsInPlace ( this , false ) ;
} ;
return RegexLiteral ;
} ) ( Expression ) ;
TypeScript . RegexLiteral = RegexLiteral ;
var StringLiteral = ( function ( _super ) {
_ _extends ( StringLiteral , _super ) ;
function StringLiteral ( text ) {
_super . call ( this , NodeType . QString ) ;
this . text = text ;
}
StringLiteral . prototype . emit = function ( emitter , tokenId , startLine ) {
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . recordSourceMappingStart ( this ) ;
emitter . emitStringLiteral ( this . text ) ;
emitter . recordSourceMappingEnd ( this ) ;
emitter . emitParensAndCommentsInPlace ( this , false ) ;
} ;
StringLiteral . prototype . typeCheck = function ( typeFlow ) {
this . type = typeFlow . stringType ;
return this ;
} ;
StringLiteral . prototype . treeViewLabel = function ( ) {
return "st: " + this . text ;
} ;
StringLiteral . prototype . printLabel = function ( ) {
return this . text ;
} ;
return StringLiteral ;
} ) ( Expression ) ;
TypeScript . StringLiteral = StringLiteral ;
var ModuleElement = ( function ( _super ) {
_ _extends ( ModuleElement , _super ) ;
function ModuleElement ( nodeType ) {
_super . call ( this , nodeType ) ;
}
return ModuleElement ;
} ) ( AST ) ;
TypeScript . ModuleElement = ModuleElement ;
var ImportDeclaration = ( function ( _super ) {
_ _extends ( ImportDeclaration , _super ) ;
function ImportDeclaration ( id , alias ) {
_super . call ( this , NodeType . ImportDeclaration ) ;
this . id = id ;
this . alias = alias ;
this . varFlags = VarFlags . None ;
this . isDynamicImport = false ;
}
2015-02-07 05:03:24 +01:00
ImportDeclaration . prototype . isStatementOrExpression = function ( ) { return true ; } ;
2015-02-03 00:30:33 +01:00
ImportDeclaration . prototype . emit = function ( emitter , tokenId , startLine ) {
var mod = this . alias . type ;
// REVIEW: Only modules may be aliased for now, though there's no real
// restriction on what the type symbol may be
if ( ! this . isDynamicImport || ( this . id . sym && ! this . id . sym . onlyReferencedAsTypeRef ) ) {
var prevModAliasId = emitter . modAliasId ;
var prevFirstModAlias = emitter . firstModAlias ;
emitter . recordSourceMappingStart ( this ) ;
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . writeToOutput ( "var " + this . id . actualText + " = " ) ;
emitter . modAliasId = this . id . actualText ;
emitter . firstModAlias = this . firstAliasedModToString ( ) ;
emitter . emitJavascript ( this . alias , TokenID . Tilde , false ) ;
// the dynamic import case will insert the semi-colon automatically
if ( ! this . isDynamicImport ) {
emitter . writeToOutput ( ";" ) ;
}
emitter . emitParensAndCommentsInPlace ( this , false ) ;
emitter . recordSourceMappingEnd ( this ) ;
emitter . modAliasId = prevModAliasId ;
emitter . firstModAlias = prevFirstModAlias ;
}
} ;
ImportDeclaration . prototype . typeCheck = function ( typeFlow ) {
return typeFlow . typeCheckImportDecl ( this ) ;
} ;
ImportDeclaration . prototype . getAliasName = function ( aliasAST ) {
if ( aliasAST === void 0 ) { aliasAST = this . alias ; }
if ( aliasAST . nodeType == NodeType . Name ) {
return aliasAST . actualText ;
}
else {
var dotExpr = aliasAST ;
return this . getAliasName ( dotExpr . operand1 ) + "." + this . getAliasName ( dotExpr . operand2 ) ;
}
} ;
ImportDeclaration . prototype . firstAliasedModToString = function ( ) {
if ( this . alias . nodeType == NodeType . Name ) {
return this . alias . actualText ;
}
else {
var dotExpr = this . alias ;
var firstMod = dotExpr . operand1 ;
return firstMod . actualText ;
}
} ;
return ImportDeclaration ;
} ) ( ModuleElement ) ;
TypeScript . ImportDeclaration = ImportDeclaration ;
var BoundDecl = ( function ( _super ) {
_ _extends ( BoundDecl , _super ) ;
function BoundDecl ( id , nodeType , nestingLevel ) {
_super . call ( this , nodeType ) ;
this . id = id ;
this . nestingLevel = nestingLevel ;
this . init = null ;
this . typeExpr = null ;
this . varFlags = VarFlags . None ;
this . sym = null ;
}
2015-02-07 05:03:24 +01:00
BoundDecl . prototype . isStatementOrExpression = function ( ) { return true ; } ;
BoundDecl . prototype . isPrivate = function ( ) { return hasFlag ( this . varFlags , VarFlags . Private ) ; } ;
BoundDecl . prototype . isPublic = function ( ) { return hasFlag ( this . varFlags , VarFlags . Public ) ; } ;
BoundDecl . prototype . isProperty = function ( ) { return hasFlag ( this . varFlags , VarFlags . Property ) ; } ;
2015-02-03 00:30:33 +01:00
BoundDecl . prototype . typeCheck = function ( typeFlow ) {
return typeFlow . typeCheckBoundDecl ( this ) ;
} ;
BoundDecl . prototype . printLabel = function ( ) {
return this . treeViewLabel ( ) ;
} ;
return BoundDecl ;
} ) ( AST ) ;
TypeScript . BoundDecl = BoundDecl ;
var VarDecl = ( function ( _super ) {
_ _extends ( VarDecl , _super ) ;
function VarDecl ( id , nest ) {
_super . call ( this , id , NodeType . VarDecl , nest ) ;
}
2015-02-07 05:03:24 +01:00
VarDecl . prototype . isAmbient = function ( ) { return hasFlag ( this . varFlags , VarFlags . Ambient ) ; } ;
VarDecl . prototype . isExported = function ( ) { return hasFlag ( this . varFlags , VarFlags . Exported ) ; } ;
VarDecl . prototype . isStatic = function ( ) { return hasFlag ( this . varFlags , VarFlags . Static ) ; } ;
2015-02-03 00:30:33 +01:00
VarDecl . prototype . emit = function ( emitter , tokenId , startLine ) {
emitter . emitJavascriptVarDecl ( this , tokenId ) ;
} ;
VarDecl . prototype . treeViewLabel = function ( ) {
return "var " + this . id . actualText ;
} ;
return VarDecl ;
} ) ( BoundDecl ) ;
TypeScript . VarDecl = VarDecl ;
var ArgDecl = ( function ( _super ) {
_ _extends ( ArgDecl , _super ) ;
function ArgDecl ( id ) {
_super . call ( this , id , NodeType . ArgDecl , 0 ) ;
this . isOptional = false ;
this . parameterPropertySym = null ;
}
2015-02-07 05:03:24 +01:00
ArgDecl . prototype . isOptionalArg = function ( ) { return this . isOptional || this . init ; } ;
2015-02-03 00:30:33 +01:00
ArgDecl . prototype . treeViewLabel = function ( ) {
return "arg: " + this . id . actualText ;
} ;
ArgDecl . prototype . emit = function ( emitter , tokenId , startLine ) {
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . recordSourceMappingStart ( this ) ;
emitter . writeToOutput ( this . id . actualText ) ;
emitter . recordSourceMappingEnd ( this ) ;
emitter . emitParensAndCommentsInPlace ( this , false ) ;
} ;
return ArgDecl ;
} ) ( BoundDecl ) ;
TypeScript . ArgDecl = ArgDecl ;
var internalId = 0 ;
var FuncDecl = ( function ( _super ) {
_ _extends ( FuncDecl , _super ) ;
function FuncDecl ( name , bod , isConstructor , arguments , vars , scopes , statics , nodeType ) {
_super . call ( this , nodeType ) ;
this . name = name ;
this . bod = bod ;
this . isConstructor = isConstructor ;
this . arguments = arguments ;
this . vars = vars ;
this . scopes = scopes ;
this . statics = statics ;
this . hint = null ;
this . fncFlags = FncFlags . None ;
this . returnTypeAnnotation = null ;
this . variableArgList = false ;
this . jumpRefs = null ;
this . internalNameCache = null ;
this . tmp1Declared = false ;
this . enclosingFnc = null ;
this . freeVariables = [ ] ;
this . unitIndex = - 1 ;
this . classDecl = null ;
this . boundToProperty = null ;
this . isOverload = false ;
this . innerStaticFuncs = [ ] ;
this . isTargetTypedAsMethod = false ;
this . isInlineCallLiteral = false ;
this . accessorSymbol = null ;
this . leftCurlyCount = 0 ;
this . rightCurlyCount = 0 ;
this . returnStatementsWithExpressions = [ ] ;
this . scopeType = null ; // Type of the FuncDecl, before target typing
this . endingToken = null ;
}
FuncDecl . prototype . internalName = function ( ) {
if ( this . internalNameCache == null ) {
var extName = this . getNameText ( ) ;
if ( extName ) {
this . internalNameCache = "_internal_" + extName ;
}
else {
this . internalNameCache = "_internal_" + internalId ++ ;
}
}
return this . internalNameCache ;
} ;
2015-02-07 05:03:24 +01:00
FuncDecl . prototype . hasSelfReference = function ( ) { return hasFlag ( this . fncFlags , FncFlags . HasSelfReference ) ; } ;
FuncDecl . prototype . setHasSelfReference = function ( ) { this . fncFlags |= FncFlags . HasSelfReference ; } ;
2015-02-03 00:30:33 +01:00
FuncDecl . prototype . addCloRef = function ( id , sym ) {
if ( this . envids == null ) {
this . envids = new Identifier [ ] ;
}
this . envids [ this . envids . length ] = id ;
var outerFnc = this . enclosingFnc ;
if ( sym ) {
while ( outerFnc && ( outerFnc . type . symbol != sym . container ) ) {
outerFnc . addJumpRef ( sym ) ;
outerFnc = outerFnc . enclosingFnc ;
}
}
return this . envids . length - 1 ;
} ;
FuncDecl . prototype . addJumpRef = function ( sym ) {
if ( this . jumpRefs == null ) {
this . jumpRefs = new Identifier [ ] ;
}
var id = new Identifier ( sym . name ) ;
this . jumpRefs [ this . jumpRefs . length ] = id ;
id . sym = sym ;
id . cloId = this . addCloRef ( id , null ) ;
} ;
FuncDecl . prototype . buildControlFlow = function ( ) {
var entry = new BasicBlock ( ) ;
var exit = new BasicBlock ( ) ;
var context = new ControlFlowContext ( entry , exit ) ;
var controlFlowPrefix = function ( ast , parent , walker ) {
ast . addToControlFlow ( walker . state ) ;
return ast ;
} ;
var walker = getAstWalkerFactory ( ) . getWalker ( controlFlowPrefix , null , null , context ) ;
context . walker = walker ;
walker . walk ( this . bod , this ) ;
return context ;
} ;
FuncDecl . prototype . typeCheck = function ( typeFlow ) {
return typeFlow . typeCheckFunction ( this ) ;
} ;
FuncDecl . prototype . emit = function ( emitter , tokenId , startLine ) {
emitter . emitJavascriptFunction ( this ) ;
} ;
FuncDecl . prototype . getNameText = function ( ) {
if ( this . name ) {
return this . name . actualText ;
}
else {
return this . hint ;
}
} ;
FuncDecl . prototype . isMethod = function ( ) {
return ( this . fncFlags & FncFlags . Method ) != FncFlags . None ;
} ;
2015-02-07 05:03:24 +01:00
FuncDecl . prototype . isCallMember = function ( ) { return hasFlag ( this . fncFlags , FncFlags . CallMember ) ; } ;
FuncDecl . prototype . isConstructMember = function ( ) { return hasFlag ( this . fncFlags , FncFlags . ConstructMember ) ; } ;
FuncDecl . prototype . isIndexerMember = function ( ) { return hasFlag ( this . fncFlags , FncFlags . IndexerMember ) ; } ;
FuncDecl . prototype . isSpecialFn = function ( ) { return this . isCallMember ( ) || this . isIndexerMember ( ) || this . isConstructMember ( ) ; } ;
FuncDecl . prototype . isAnonymousFn = function ( ) { return this . name === null ; } ;
FuncDecl . prototype . isAccessor = function ( ) { return hasFlag ( this . fncFlags , FncFlags . GetAccessor ) || hasFlag ( this . fncFlags , FncFlags . SetAccessor ) ; } ;
FuncDecl . prototype . isGetAccessor = function ( ) { return hasFlag ( this . fncFlags , FncFlags . GetAccessor ) ; } ;
FuncDecl . prototype . isSetAccessor = function ( ) { return hasFlag ( this . fncFlags , FncFlags . SetAccessor ) ; } ;
FuncDecl . prototype . isAmbient = function ( ) { return hasFlag ( this . fncFlags , FncFlags . Ambient ) ; } ;
FuncDecl . prototype . isExported = function ( ) { return hasFlag ( this . fncFlags , FncFlags . Exported ) ; } ;
FuncDecl . prototype . isPrivate = function ( ) { return hasFlag ( this . fncFlags , FncFlags . Private ) ; } ;
FuncDecl . prototype . isPublic = function ( ) { return hasFlag ( this . fncFlags , FncFlags . Public ) ; } ;
FuncDecl . prototype . isStatic = function ( ) { return hasFlag ( this . fncFlags , FncFlags . Static ) ; } ;
2015-02-03 00:30:33 +01:00
FuncDecl . prototype . treeViewLabel = function ( ) {
if ( this . name == null ) {
return "funcExpr" ;
}
else {
return "func: " + this . name . actualText ;
}
} ;
FuncDecl . prototype . ClearFlags = function ( ) {
this . fncFlags = FncFlags . None ;
} ;
2015-02-07 05:03:24 +01:00
FuncDecl . prototype . isSignature = function ( ) { return ( this . fncFlags & FncFlags . Signature ) != FncFlags . None ; } ;
FuncDecl . prototype . hasStaticDeclarations = function ( ) { return ( ! this . isConstructor && ( this . statics . members . length > 0 || this . innerStaticFuncs . length > 0 ) ) ; } ;
2015-02-03 00:30:33 +01:00
return FuncDecl ;
} ) ( AST ) ;
TypeScript . FuncDecl = FuncDecl ;
var LocationInfo = ( function ( ) {
function LocationInfo ( filename , lineMap , unitIndex ) {
this . filename = filename ;
this . lineMap = lineMap ;
this . unitIndex = unitIndex ;
}
return LocationInfo ;
} ) ( ) ;
TypeScript . LocationInfo = LocationInfo ;
TypeScript . unknownLocationInfo = new LocationInfo ( "unknown" , null , - 1 ) ;
var Script = ( function ( _super ) {
_ _extends ( Script , _super ) ;
function Script ( vars , scopes ) {
_super . call ( this , new Identifier ( "script" ) , null , false , null , vars , scopes , null , NodeType . Script ) ;
this . locationInfo = null ;
this . referencedFiles = [ ] ;
this . requiresGlobal = false ;
this . requiresInherits = false ;
this . isResident = false ;
this . isDeclareFile = false ;
this . hasBeenTypeChecked = false ;
this . topLevelMod = null ;
this . leftCurlyCount = 0 ;
this . rightCurlyCount = 0 ;
// Remember if the script contains Unicode chars, that is needed when generating code for this script object to decide the output file correct encoding.
this . containsUnicodeChar = false ;
this . containsUnicodeCharInComment = false ;
this . vars = vars ;
this . scopes = scopes ;
}
Script . prototype . typeCheck = function ( typeFlow ) {
return typeFlow . typeCheckScript ( this ) ;
} ;
Script . prototype . treeViewLabel = function ( ) {
return "Script" ;
} ;
Script . prototype . emitRequired = function ( ) {
if ( ! this . isDeclareFile && ! this . isResident && this . bod ) {
for ( var i = 0 , len = this . bod . members . length ; i < len ; i ++ ) {
var stmt = this . bod . members [ i ] ;
if ( stmt . nodeType == NodeType . ModuleDeclaration ) {
if ( ! hasFlag ( stmt . modFlags , ModuleFlags . ShouldEmitModuleDecl | ModuleFlags . Ambient ) ) {
return true ;
}
}
else if ( stmt . nodeType == NodeType . ClassDeclaration ) {
if ( ! hasFlag ( stmt . varFlags , VarFlags . Ambient ) ) {
return true ;
}
}
else if ( stmt . nodeType == NodeType . VarDecl ) {
if ( ! hasFlag ( stmt . varFlags , VarFlags . Ambient ) ) {
return true ;
}
}
else if ( stmt . nodeType == NodeType . FuncDecl ) {
if ( ! stmt . isSignature ( ) ) {
return true ;
}
}
else if ( stmt . nodeType != NodeType . InterfaceDeclaration && stmt . nodeType != NodeType . Empty ) {
return true ;
}
}
}
return false ;
} ;
Script . prototype . emit = function ( emitter , tokenId , startLine ) {
if ( this . emitRequired ( ) ) {
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . recordSourceMappingStart ( this ) ;
emitter . emitJavascriptList ( this . bod , null , TokenID . Semicolon , true , false , false , true , this . requiresInherits ) ;
emitter . recordSourceMappingEnd ( this ) ;
emitter . emitParensAndCommentsInPlace ( this , false ) ;
}
} ;
return Script ;
} ) ( FuncDecl ) ;
TypeScript . Script = Script ;
var NamedDeclaration = ( function ( _super ) {
_ _extends ( NamedDeclaration , _super ) ;
function NamedDeclaration ( nodeType , name , members ) {
_super . call ( this , nodeType ) ;
this . name = name ;
this . members = members ;
this . leftCurlyCount = 0 ;
this . rightCurlyCount = 0 ;
}
return NamedDeclaration ;
} ) ( ModuleElement ) ;
TypeScript . NamedDeclaration = NamedDeclaration ;
var ModuleDeclaration = ( function ( _super ) {
_ _extends ( ModuleDeclaration , _super ) ;
function ModuleDeclaration ( name , members , vars , scopes , endingToken ) {
_super . call ( this , NodeType . ModuleDeclaration , name , members ) ;
this . endingToken = endingToken ;
this . modFlags = ModuleFlags . ShouldEmitModuleDecl ;
this . amdDependencies = [ ] ;
// Remember if the module contains Unicode chars, that is needed for dynamic module as we will generate a file for each.
this . containsUnicodeChar = false ;
this . containsUnicodeCharInComment = false ;
this . vars = vars ;
this . scopes = scopes ;
this . prettyName = this . name . actualText ;
}
2015-02-07 05:03:24 +01:00
ModuleDeclaration . prototype . isExported = function ( ) { return hasFlag ( this . modFlags , ModuleFlags . Exported ) ; } ;
ModuleDeclaration . prototype . isAmbient = function ( ) { return hasFlag ( this . modFlags , ModuleFlags . Ambient ) ; } ;
ModuleDeclaration . prototype . isEnum = function ( ) { return hasFlag ( this . modFlags , ModuleFlags . IsEnum ) ; } ;
2015-02-03 00:30:33 +01:00
ModuleDeclaration . prototype . recordNonInterface = function ( ) {
this . modFlags &= ~ ModuleFlags . ShouldEmitModuleDecl ;
} ;
ModuleDeclaration . prototype . typeCheck = function ( typeFlow ) {
return typeFlow . typeCheckModule ( this ) ;
} ;
ModuleDeclaration . prototype . emit = function ( emitter , tokenId , startLine ) {
if ( ! hasFlag ( this . modFlags , ModuleFlags . ShouldEmitModuleDecl ) ) {
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . recordSourceMappingStart ( this ) ;
emitter . emitJavascriptModule ( this ) ;
emitter . recordSourceMappingEnd ( this ) ;
emitter . emitParensAndCommentsInPlace ( this , false ) ;
}
} ;
return ModuleDeclaration ;
} ) ( NamedDeclaration ) ;
TypeScript . ModuleDeclaration = ModuleDeclaration ;
var TypeDeclaration = ( function ( _super ) {
_ _extends ( TypeDeclaration , _super ) ;
function TypeDeclaration ( nodeType , name , extendsList , implementsList , members ) {
_super . call ( this , nodeType , name , members ) ;
this . extendsList = extendsList ;
this . implementsList = implementsList ;
this . varFlags = VarFlags . None ;
}
TypeDeclaration . prototype . isExported = function ( ) {
return hasFlag ( this . varFlags , VarFlags . Exported ) ;
} ;
TypeDeclaration . prototype . isAmbient = function ( ) {
return hasFlag ( this . varFlags , VarFlags . Ambient ) ;
} ;
return TypeDeclaration ;
} ) ( NamedDeclaration ) ;
TypeScript . TypeDeclaration = TypeDeclaration ;
var ClassDeclaration = ( function ( _super ) {
_ _extends ( ClassDeclaration , _super ) ;
function ClassDeclaration ( name , members , extendsList , implementsList ) {
_super . call ( this , NodeType . ClassDeclaration , name , extendsList , implementsList , members ) ;
this . knownMemberNames = { } ;
this . constructorDecl = null ;
this . constructorNestingLevel = 0 ;
this . endingToken = null ;
}
ClassDeclaration . prototype . typeCheck = function ( typeFlow ) {
return typeFlow . typeCheckClass ( this ) ;
} ;
ClassDeclaration . prototype . emit = function ( emitter , tokenId , startLine ) {
emitter . emitJavascriptClass ( this ) ;
} ;
return ClassDeclaration ;
} ) ( TypeDeclaration ) ;
TypeScript . ClassDeclaration = ClassDeclaration ;
var InterfaceDeclaration = ( function ( _super ) {
_ _extends ( InterfaceDeclaration , _super ) ;
function InterfaceDeclaration ( name , members , extendsList , implementsList ) {
_super . call ( this , NodeType . InterfaceDeclaration , name , extendsList , implementsList , members ) ;
}
InterfaceDeclaration . prototype . typeCheck = function ( typeFlow ) {
return typeFlow . typeCheckInterface ( this ) ;
} ;
InterfaceDeclaration . prototype . emit = function ( emitter , tokenId , startLine ) {
} ;
return InterfaceDeclaration ;
} ) ( TypeDeclaration ) ;
TypeScript . InterfaceDeclaration = InterfaceDeclaration ;
var Statement = ( function ( _super ) {
_ _extends ( Statement , _super ) ;
function Statement ( nodeType ) {
_super . call ( this , nodeType ) ;
this . flags |= ASTFlags . IsStatement ;
}
2015-02-07 05:03:24 +01:00
Statement . prototype . isLoop = function ( ) { return false ; } ;
Statement . prototype . isStatementOrExpression = function ( ) { return true ; } ;
Statement . prototype . isCompoundStatement = function ( ) { return this . isLoop ( ) ; } ;
2015-02-03 00:30:33 +01:00
Statement . prototype . typeCheck = function ( typeFlow ) {
this . type = typeFlow . voidType ;
return this ;
} ;
return Statement ;
} ) ( ModuleElement ) ;
TypeScript . Statement = Statement ;
var LabeledStatement = ( function ( _super ) {
_ _extends ( LabeledStatement , _super ) ;
function LabeledStatement ( labels , stmt ) {
_super . call ( this , NodeType . LabeledStatement ) ;
this . labels = labels ;
this . stmt = stmt ;
}
LabeledStatement . prototype . emit = function ( emitter , tokenId , startLine ) {
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . recordSourceMappingStart ( this ) ;
if ( this . labels ) {
var labelsLen = this . labels . members . length ;
for ( var i = 0 ; i < labelsLen ; i ++ ) {
this . labels . members [ i ] . emit ( emitter , tokenId , startLine ) ;
}
}
this . stmt . emit ( emitter , tokenId , true ) ;
emitter . recordSourceMappingEnd ( this ) ;
emitter . emitParensAndCommentsInPlace ( this , false ) ;
} ;
LabeledStatement . prototype . typeCheck = function ( typeFlow ) {
typeFlow . typeCheck ( this . labels ) ;
this . stmt = this . stmt . typeCheck ( typeFlow ) ;
return this ;
} ;
LabeledStatement . prototype . addToControlFlow = function ( context ) {
var beforeBB = context . current ;
var bb = new BasicBlock ( ) ;
context . current = bb ;
beforeBB . addSuccessor ( bb ) ;
} ;
return LabeledStatement ;
} ) ( Statement ) ;
TypeScript . LabeledStatement = LabeledStatement ;
var Block = ( function ( _super ) {
_ _extends ( Block , _super ) ;
function Block ( statements , isStatementBlock ) {
_super . call ( this , NodeType . Block ) ;
this . statements = statements ;
this . isStatementBlock = isStatementBlock ;
}
Block . prototype . emit = function ( emitter , tokenId , startLine ) {
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . recordSourceMappingStart ( this ) ;
if ( this . isStatementBlock ) {
emitter . writeLineToOutput ( " {" ) ;
emitter . indenter . increaseIndent ( ) ;
}
else {
emitter . setInVarBlock ( this . statements . members . length ) ;
}
var temp = emitter . setInObjectLiteral ( false ) ;
if ( this . statements ) {
emitter . emitJavascriptList ( this . statements , null , TokenID . Semicolon , true , false , false ) ;
}
if ( this . isStatementBlock ) {
emitter . indenter . decreaseIndent ( ) ;
emitter . emitIndent ( ) ;
emitter . writeToOutput ( "}" ) ;
}
emitter . setInObjectLiteral ( temp ) ;
emitter . recordSourceMappingEnd ( this ) ;
emitter . emitParensAndCommentsInPlace ( this , false ) ;
} ;
Block . prototype . addToControlFlow = function ( context ) {
var afterIfNeeded = new BasicBlock ( ) ;
context . pushStatement ( this , context . current , afterIfNeeded ) ;
if ( this . statements ) {
context . walk ( this . statements , this ) ;
}
context . walker . options . goChildren = false ;
context . popStatement ( ) ;
if ( afterIfNeeded . predecessors . length > 0 ) {
context . current . addSuccessor ( afterIfNeeded ) ;
context . current = afterIfNeeded ;
}
} ;
Block . prototype . typeCheck = function ( typeFlow ) {
if ( ! typeFlow . checker . styleSettings . emptyBlocks ) {
if ( ( this . statements === null ) || ( this . statements . members . length == 0 ) ) {
typeFlow . checker . errorReporter . styleError ( this , "empty block" ) ;
}
}
typeFlow . typeCheck ( this . statements ) ;
return this ;
} ;
return Block ;
} ) ( Statement ) ;
TypeScript . Block = Block ;
var Jump = ( function ( _super ) {
_ _extends ( Jump , _super ) ;
function Jump ( nodeType ) {
_super . call ( this , nodeType ) ;
this . target = null ;
this . resolvedTarget = null ;
}
2015-02-07 05:03:24 +01:00
Jump . prototype . hasExplicitTarget = function ( ) { return ( this . target ) ; } ;
2015-02-03 00:30:33 +01:00
Jump . prototype . setResolvedTarget = function ( parser , stmt ) {
if ( stmt . isLoop ( ) ) {
this . resolvedTarget = stmt ;
return true ;
}
if ( this . nodeType === NodeType . Continue ) {
parser . reportParseError ( "continue statement applies only to loops" ) ;
return false ;
}
else {
if ( ( stmt . nodeType == NodeType . Switch ) || this . hasExplicitTarget ( ) ) {
this . resolvedTarget = stmt ;
return true ;
}
else {
parser . reportParseError ( "break statement with no label can apply only to a loop or switch statement" ) ;
return false ;
}
}
} ;
Jump . prototype . addToControlFlow = function ( context ) {
_super . prototype . addToControlFlow . call ( this , context ) ;
context . unconditionalBranch ( this . resolvedTarget , ( this . nodeType == NodeType . Continue ) ) ;
} ;
Jump . prototype . emit = function ( emitter , tokenId , startLine ) {
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . recordSourceMappingStart ( this ) ;
if ( this . nodeType == NodeType . Break ) {
emitter . writeToOutput ( "break" ) ;
}
else {
emitter . writeToOutput ( "continue" ) ;
}
if ( this . hasExplicitTarget ( ) ) {
emitter . writeToOutput ( " " + this . target ) ;
}
emitter . recordSourceMappingEnd ( this ) ;
emitter . writeToOutput ( ";" ) ;
emitter . emitParensAndCommentsInPlace ( this , false ) ;
} ;
return Jump ;
} ) ( Statement ) ;
TypeScript . Jump = Jump ;
var WhileStatement = ( function ( _super ) {
_ _extends ( WhileStatement , _super ) ;
function WhileStatement ( cond ) {
_super . call ( this , NodeType . While ) ;
this . cond = cond ;
this . body = null ;
}
2015-02-07 05:03:24 +01:00
WhileStatement . prototype . isLoop = function ( ) { return true ; } ;
2015-02-03 00:30:33 +01:00
WhileStatement . prototype . emit = function ( emitter , tokenId , startLine ) {
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . recordSourceMappingStart ( this ) ;
var temp = emitter . setInObjectLiteral ( false ) ;
emitter . writeToOutput ( "while(" ) ;
emitter . emitJavascript ( this . cond , TokenID . While , false ) ;
emitter . writeToOutput ( ")" ) ;
emitter . emitJavascriptStatements ( this . body , false , false ) ;
emitter . setInObjectLiteral ( temp ) ;
emitter . recordSourceMappingEnd ( this ) ;
emitter . emitParensAndCommentsInPlace ( this , false ) ;
} ;
WhileStatement . prototype . typeCheck = function ( typeFlow ) {
return typeFlow . typeCheckWhile ( this ) ;
} ;
WhileStatement . prototype . addToControlFlow = function ( context ) {
var loopHeader = context . current ;
var loopStart = new BasicBlock ( ) ;
var afterLoop = new BasicBlock ( ) ;
loopHeader . addSuccessor ( loopStart ) ;
context . current = loopStart ;
context . addContent ( this . cond ) ;
var condBlock = context . current ;
var targetInfo = null ;
if ( this . body ) {
context . current = new BasicBlock ( ) ;
condBlock . addSuccessor ( context . current ) ;
context . pushStatement ( this , loopStart , afterLoop ) ;
context . walk ( this . body , this ) ;
targetInfo = context . popStatement ( ) ;
}
if ( ! ( context . noContinuation ) ) {
var loopEnd = context . current ;
loopEnd . addSuccessor ( loopStart ) ;
}
context . current = afterLoop ;
condBlock . addSuccessor ( afterLoop ) ;
// TODO: check for while (true) and then only continue if afterLoop has predecessors
context . noContinuation = false ;
context . walker . options . goChildren = false ;
} ;
return WhileStatement ;
} ) ( Statement ) ;
TypeScript . WhileStatement = WhileStatement ;
var DoWhileStatement = ( function ( _super ) {
_ _extends ( DoWhileStatement , _super ) ;
function DoWhileStatement ( ) {
_super . call ( this , NodeType . DoWhile ) ;
this . body = null ;
this . whileAST = null ;
this . cond = null ;
}
2015-02-07 05:03:24 +01:00
DoWhileStatement . prototype . isLoop = function ( ) { return true ; } ;
2015-02-03 00:30:33 +01:00
DoWhileStatement . prototype . emit = function ( emitter , tokenId , startLine ) {
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . recordSourceMappingStart ( this ) ;
var temp = emitter . setInObjectLiteral ( false ) ;
emitter . writeToOutput ( "do" ) ;
emitter . emitJavascriptStatements ( this . body , true , false ) ;
emitter . recordSourceMappingStart ( this . whileAST ) ;
emitter . writeToOutput ( "while" ) ;
emitter . recordSourceMappingEnd ( this . whileAST ) ;
emitter . writeToOutput ( '(' ) ;
emitter . emitJavascript ( this . cond , TokenID . CloseParen , false ) ;
emitter . writeToOutput ( ")" ) ;
emitter . setInObjectLiteral ( temp ) ;
emitter . recordSourceMappingEnd ( this ) ;
emitter . emitParensAndCommentsInPlace ( this , false ) ;
} ;
DoWhileStatement . prototype . typeCheck = function ( typeFlow ) {
return typeFlow . typeCheckDoWhile ( this ) ;
} ;
DoWhileStatement . prototype . addToControlFlow = function ( context ) {
var loopHeader = context . current ;
var loopStart = new BasicBlock ( ) ;
var afterLoop = new BasicBlock ( ) ;
loopHeader . addSuccessor ( loopStart ) ;
context . current = loopStart ;
var targetInfo = null ;
if ( this . body ) {
context . pushStatement ( this , loopStart , afterLoop ) ;
context . walk ( this . body , this ) ;
targetInfo = context . popStatement ( ) ;
}
if ( ! ( context . noContinuation ) ) {
var loopEnd = context . current ;
loopEnd . addSuccessor ( loopStart ) ;
context . addContent ( this . cond ) ;
// TODO: check for while (true)
context . current = afterLoop ;
loopEnd . addSuccessor ( afterLoop ) ;
}
else {
context . addUnreachable ( this . cond ) ;
}
context . walker . options . goChildren = false ;
} ;
return DoWhileStatement ;
} ) ( Statement ) ;
TypeScript . DoWhileStatement = DoWhileStatement ;
var IfStatement = ( function ( _super ) {
_ _extends ( IfStatement , _super ) ;
function IfStatement ( cond ) {
_super . call ( this , NodeType . If ) ;
this . cond = cond ;
this . elseBod = null ;
this . statement = new ASTSpan ( ) ;
}
2015-02-07 05:03:24 +01:00
IfStatement . prototype . isCompoundStatement = function ( ) { return true ; } ;
2015-02-03 00:30:33 +01:00
IfStatement . prototype . emit = function ( emitter , tokenId , startLine ) {
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . recordSourceMappingStart ( this ) ;
var temp = emitter . setInObjectLiteral ( false ) ;
emitter . recordSourceMappingStart ( this . statement ) ;
emitter . writeToOutput ( "if(" ) ;
emitter . emitJavascript ( this . cond , TokenID . If , false ) ;
emitter . writeToOutput ( ")" ) ;
emitter . recordSourceMappingEnd ( this . statement ) ;
emitter . emitJavascriptStatements ( this . thenBod , true , false ) ;
if ( this . elseBod ) {
emitter . writeToOutput ( " else" ) ;
emitter . emitJavascriptStatements ( this . elseBod , true , true ) ;
}
emitter . setInObjectLiteral ( temp ) ;
emitter . recordSourceMappingEnd ( this ) ;
emitter . emitParensAndCommentsInPlace ( this , false ) ;
} ;
IfStatement . prototype . typeCheck = function ( typeFlow ) {
return typeFlow . typeCheckIf ( this ) ;
} ;
IfStatement . prototype . addToControlFlow = function ( context ) {
this . cond . addToControlFlow ( context ) ;
var afterIf = new BasicBlock ( ) ;
var beforeIf = context . current ;
context . pushStatement ( this , beforeIf , afterIf ) ;
var hasContinuation = false ;
context . current = new BasicBlock ( ) ;
beforeIf . addSuccessor ( context . current ) ;
context . walk ( this . thenBod , this ) ;
if ( ! context . noContinuation ) {
hasContinuation = true ;
context . current . addSuccessor ( afterIf ) ;
}
if ( this . elseBod ) {
// current block will be thenBod
context . current = new BasicBlock ( ) ;
context . noContinuation = false ;
beforeIf . addSuccessor ( context . current ) ;
context . walk ( this . elseBod , this ) ;
if ( ! context . noContinuation ) {
hasContinuation = true ;
context . current . addSuccessor ( afterIf ) ;
}
else {
// thenBod created continuation for if statement
if ( hasContinuation ) {
context . noContinuation = false ;
}
}
}
else {
beforeIf . addSuccessor ( afterIf ) ;
context . noContinuation = false ;
hasContinuation = true ;
}
var targetInfo = context . popStatement ( ) ;
if ( afterIf . predecessors . length > 0 ) {
context . noContinuation = false ;
hasContinuation = true ;
}
if ( hasContinuation ) {
context . current = afterIf ;
}
context . walker . options . goChildren = false ;
} ;
return IfStatement ;
} ) ( Statement ) ;
TypeScript . IfStatement = IfStatement ;
var ReturnStatement = ( function ( _super ) {
_ _extends ( ReturnStatement , _super ) ;
function ReturnStatement ( ) {
_super . call ( this , NodeType . Return ) ;
this . returnExpression = null ;
}
ReturnStatement . prototype . emit = function ( emitter , tokenId , startLine ) {
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . recordSourceMappingStart ( this ) ;
var temp = emitter . setInObjectLiteral ( false ) ;
if ( this . returnExpression ) {
emitter . writeToOutput ( "return " ) ;
emitter . emitJavascript ( this . returnExpression , TokenID . Semicolon , false ) ;
}
else {
emitter . writeToOutput ( "return;" ) ;
}
emitter . setInObjectLiteral ( temp ) ;
emitter . recordSourceMappingEnd ( this ) ;
emitter . emitParensAndCommentsInPlace ( this , false ) ;
} ;
ReturnStatement . prototype . addToControlFlow = function ( context ) {
_super . prototype . addToControlFlow . call ( this , context ) ;
context . returnStmt ( ) ;
} ;
ReturnStatement . prototype . typeCheck = function ( typeFlow ) {
return typeFlow . typeCheckReturn ( this ) ;
} ;
return ReturnStatement ;
} ) ( Statement ) ;
TypeScript . ReturnStatement = ReturnStatement ;
var EndCode = ( function ( _super ) {
_ _extends ( EndCode , _super ) ;
function EndCode ( ) {
_super . call ( this , NodeType . EndCode ) ;
}
return EndCode ;
} ) ( AST ) ;
TypeScript . EndCode = EndCode ;
var ForInStatement = ( function ( _super ) {
_ _extends ( ForInStatement , _super ) ;
function ForInStatement ( lval , obj ) {
_super . call ( this , NodeType . ForIn ) ;
this . lval = lval ;
this . obj = obj ;
this . statement = new ASTSpan ( ) ;
if ( this . lval && ( this . lval . nodeType == NodeType . VarDecl ) ) {
this . lval . varFlags |= VarFlags . AutoInit ;
}
}
2015-02-07 05:03:24 +01:00
ForInStatement . prototype . isLoop = function ( ) { return true ; } ;
2015-02-03 00:30:33 +01:00
ForInStatement . prototype . isFiltered = function ( ) {
if ( this . body ) {
var singleItem = null ;
if ( this . body . nodeType == NodeType . List ) {
var stmts = this . body ;
if ( stmts . members . length == 1 ) {
singleItem = stmts . members [ 0 ] ;
}
}
else {
singleItem = this . body ;
}
// match template for filtering 'own' properties from obj
if ( singleItem !== null ) {
if ( singleItem . nodeType == NodeType . Block ) {
var block = singleItem ;
if ( ( block . statements !== null ) && ( block . statements . members . length == 1 ) ) {
singleItem = block . statements . members [ 0 ] ;
}
}
if ( singleItem . nodeType == NodeType . If ) {
var cond = singleItem . cond ;
if ( cond . nodeType == NodeType . Call ) {
var target = cond . target ;
if ( target . nodeType == NodeType . Dot ) {
var binex = target ;
2015-02-21 06:53:44 +01:00
if ( ( binex . operand1 . nodeType == NodeType . Name ) &&
( this . obj . nodeType == NodeType . Name ) &&
( binex . operand1 . actualText == this . obj . actualText ) ) {
2015-02-03 00:30:33 +01:00
var prop = binex . operand2 ;
if ( prop . actualText == "hasOwnProperty" ) {
var args = cond . arguments ;
if ( ( args !== null ) && ( args . members . length == 1 ) ) {
var arg = args . members [ 0 ] ;
2015-02-21 06:53:44 +01:00
if ( ( arg . nodeType == NodeType . Name ) &&
( this . lval . nodeType == NodeType . Name ) ) {
2015-02-03 00:30:33 +01:00
if ( ( this . lval . actualText ) == arg . actualText ) {
return true ;
}
}
}
}
}
}
}
}
}
}
return false ;
} ;
ForInStatement . prototype . emit = function ( emitter , tokenId , startLine ) {
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . recordSourceMappingStart ( this ) ;
var temp = emitter . setInObjectLiteral ( false ) ;
emitter . recordSourceMappingStart ( this . statement ) ;
emitter . writeToOutput ( "for(" ) ;
emitter . emitJavascript ( this . lval , TokenID . For , false ) ;
emitter . writeToOutput ( " in " ) ;
emitter . emitJavascript ( this . obj , TokenID . For , false ) ;
emitter . writeToOutput ( ")" ) ;
emitter . recordSourceMappingEnd ( this . statement ) ;
emitter . emitJavascriptStatements ( this . body , true , false ) ;
emitter . setInObjectLiteral ( temp ) ;
emitter . recordSourceMappingEnd ( this ) ;
emitter . emitParensAndCommentsInPlace ( this , false ) ;
} ;
ForInStatement . prototype . typeCheck = function ( typeFlow ) {
if ( typeFlow . checker . styleSettings . forin ) {
if ( ! this . isFiltered ( ) ) {
typeFlow . checker . errorReporter . styleError ( this , "no hasOwnProperty filter" ) ;
}
}
return typeFlow . typeCheckForIn ( this ) ;
} ;
ForInStatement . prototype . addToControlFlow = function ( context ) {
if ( this . lval ) {
context . addContent ( this . lval ) ;
}
if ( this . obj ) {
context . addContent ( this . obj ) ;
}
var loopHeader = context . current ;
var loopStart = new BasicBlock ( ) ;
var afterLoop = new BasicBlock ( ) ;
loopHeader . addSuccessor ( loopStart ) ;
context . current = loopStart ;
if ( this . body ) {
context . pushStatement ( this , loopStart , afterLoop ) ;
context . walk ( this . body , this ) ;
context . popStatement ( ) ;
}
if ( ! ( context . noContinuation ) ) {
var loopEnd = context . current ;
loopEnd . addSuccessor ( loopStart ) ;
}
context . current = afterLoop ;
context . noContinuation = false ;
loopHeader . addSuccessor ( afterLoop ) ;
context . walker . options . goChildren = false ;
} ;
return ForInStatement ;
} ) ( Statement ) ;
TypeScript . ForInStatement = ForInStatement ;
var ForStatement = ( function ( _super ) {
_ _extends ( ForStatement , _super ) ;
function ForStatement ( init ) {
_super . call ( this , NodeType . For ) ;
this . init = init ;
}
2015-02-07 05:03:24 +01:00
ForStatement . prototype . isLoop = function ( ) { return true ; } ;
2015-02-03 00:30:33 +01:00
ForStatement . prototype . emit = function ( emitter , tokenId , startLine ) {
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . recordSourceMappingStart ( this ) ;
var temp = emitter . setInObjectLiteral ( false ) ;
emitter . writeToOutput ( "for(" ) ;
if ( this . init ) {
if ( this . init . nodeType != NodeType . List ) {
emitter . emitJavascript ( this . init , TokenID . For , false ) ;
}
else {
emitter . setInVarBlock ( this . init . members . length ) ;
emitter . emitJavascriptList ( this . init , null , TokenID . For , false , false , false ) ;
}
}
emitter . writeToOutput ( "; " ) ;
emitter . emitJavascript ( this . cond , TokenID . For , false ) ;
emitter . writeToOutput ( "; " ) ;
emitter . emitJavascript ( this . incr , TokenID . For , false ) ;
emitter . writeToOutput ( ")" ) ;
emitter . emitJavascriptStatements ( this . body , true , false ) ;
emitter . setInObjectLiteral ( temp ) ;
emitter . recordSourceMappingEnd ( this ) ;
emitter . emitParensAndCommentsInPlace ( this , false ) ;
} ;
ForStatement . prototype . typeCheck = function ( typeFlow ) {
return typeFlow . typeCheckFor ( this ) ;
} ;
ForStatement . prototype . addToControlFlow = function ( context ) {
if ( this . init ) {
context . addContent ( this . init ) ;
}
var loopHeader = context . current ;
var loopStart = new BasicBlock ( ) ;
var afterLoop = new BasicBlock ( ) ;
loopHeader . addSuccessor ( loopStart ) ;
context . current = loopStart ;
var condBlock = null ;
var continueTarget = loopStart ;
var incrBB = null ;
if ( this . incr ) {
incrBB = new BasicBlock ( ) ;
continueTarget = incrBB ;
}
if ( this . cond ) {
condBlock = context . current ;
context . addContent ( this . cond ) ;
context . current = new BasicBlock ( ) ;
condBlock . addSuccessor ( context . current ) ;
}
var targetInfo = null ;
if ( this . body ) {
context . pushStatement ( this , continueTarget , afterLoop ) ;
context . walk ( this . body , this ) ;
targetInfo = context . popStatement ( ) ;
}
if ( this . incr ) {
if ( context . noContinuation ) {
if ( incrBB . predecessors . length == 0 ) {
context . addUnreachable ( this . incr ) ;
}
}
else {
context . current . addSuccessor ( incrBB ) ;
context . current = incrBB ;
context . addContent ( this . incr ) ;
}
}
var loopEnd = context . current ;
if ( ! ( context . noContinuation ) ) {
loopEnd . addSuccessor ( loopStart ) ;
}
if ( condBlock ) {
condBlock . addSuccessor ( afterLoop ) ;
context . noContinuation = false ;
}
if ( afterLoop . predecessors . length > 0 ) {
context . noContinuation = false ;
context . current = afterLoop ;
}
context . walker . options . goChildren = false ;
} ;
return ForStatement ;
} ) ( Statement ) ;
TypeScript . ForStatement = ForStatement ;
var WithStatement = ( function ( _super ) {
_ _extends ( WithStatement , _super ) ;
function WithStatement ( expr ) {
_super . call ( this , NodeType . With ) ;
this . expr = expr ;
this . withSym = null ;
}
2015-02-07 05:03:24 +01:00
WithStatement . prototype . isCompoundStatement = function ( ) { return true ; } ;
2015-02-03 00:30:33 +01:00
WithStatement . prototype . emit = function ( emitter , tokenId , startLine ) {
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . recordSourceMappingStart ( this ) ;
emitter . writeToOutput ( "with (" ) ;
if ( this . expr ) {
emitter . emitJavascript ( this . expr , TokenID . With , false ) ;
}
emitter . writeToOutput ( ")" ) ;
emitter . emitJavascriptStatements ( this . body , true , false ) ;
emitter . recordSourceMappingEnd ( this ) ;
emitter . emitParensAndCommentsInPlace ( this , false ) ;
} ;
WithStatement . prototype . typeCheck = function ( typeFlow ) {
return typeFlow . typeCheckWith ( this ) ;
} ;
return WithStatement ;
} ) ( Statement ) ;
TypeScript . WithStatement = WithStatement ;
var SwitchStatement = ( function ( _super ) {
_ _extends ( SwitchStatement , _super ) ;
function SwitchStatement ( val ) {
_super . call ( this , NodeType . Switch ) ;
this . val = val ;
this . defaultCase = null ;
this . statement = new ASTSpan ( ) ;
}
2015-02-07 05:03:24 +01:00
SwitchStatement . prototype . isCompoundStatement = function ( ) { return true ; } ;
2015-02-03 00:30:33 +01:00
SwitchStatement . prototype . emit = function ( emitter , tokenId , startLine ) {
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . recordSourceMappingStart ( this ) ;
var temp = emitter . setInObjectLiteral ( false ) ;
emitter . recordSourceMappingStart ( this . statement ) ;
emitter . writeToOutput ( "switch(" ) ;
emitter . emitJavascript ( this . val , TokenID . Identifier , false ) ;
emitter . writeToOutput ( ")" ) ;
emitter . recordSourceMappingEnd ( this . statement ) ;
emitter . writeLineToOutput ( " {" ) ;
emitter . indenter . increaseIndent ( ) ;
var casesLen = this . caseList . members . length ;
for ( var i = 0 ; i < casesLen ; i ++ ) {
var caseExpr = this . caseList . members [ i ] ;
emitter . emitJavascript ( caseExpr , TokenID . Case , true ) ;
emitter . writeLineToOutput ( "" ) ;
}
emitter . indenter . decreaseIndent ( ) ;
emitter . emitIndent ( ) ;
emitter . writeToOutput ( "}" ) ;
emitter . setInObjectLiteral ( temp ) ;
emitter . recordSourceMappingEnd ( this ) ;
emitter . emitParensAndCommentsInPlace ( this , false ) ;
} ;
SwitchStatement . prototype . typeCheck = function ( typeFlow ) {
var len = this . caseList . members . length ;
this . val = typeFlow . typeCheck ( this . val ) ;
for ( var i = 0 ; i < len ; i ++ ) {
this . caseList . members [ i ] = typeFlow . typeCheck ( this . caseList . members [ i ] ) ;
}
this . defaultCase = typeFlow . typeCheck ( this . defaultCase ) ;
this . type = typeFlow . voidType ;
return this ;
} ;
// if there are break statements that match this switch, then just link cond block with block after switch
SwitchStatement . prototype . addToControlFlow = function ( context ) {
var condBlock = context . current ;
context . addContent ( this . val ) ;
var execBlock = new BasicBlock ( ) ;
var afterSwitch = new BasicBlock ( ) ;
condBlock . addSuccessor ( execBlock ) ;
context . pushSwitch ( execBlock ) ;
context . current = execBlock ;
context . pushStatement ( this , execBlock , afterSwitch ) ;
context . walk ( this . caseList , this ) ;
context . popSwitch ( ) ;
var targetInfo = context . popStatement ( ) ;
var hasCondContinuation = ( this . defaultCase == null ) ;
if ( this . defaultCase == null ) {
condBlock . addSuccessor ( afterSwitch ) ;
}
if ( afterSwitch . predecessors . length > 0 ) {
context . noContinuation = false ;
context . current = afterSwitch ;
}
else {
context . noContinuation = true ;
}
context . walker . options . goChildren = false ;
} ;
return SwitchStatement ;
} ) ( Statement ) ;
TypeScript . SwitchStatement = SwitchStatement ;
var CaseStatement = ( function ( _super ) {
_ _extends ( CaseStatement , _super ) ;
function CaseStatement ( ) {
_super . call ( this , NodeType . Case ) ;
this . expr = null ;
}
CaseStatement . prototype . emit = function ( emitter , tokenId , startLine ) {
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . recordSourceMappingStart ( this ) ;
if ( this . expr ) {
emitter . writeToOutput ( "case " ) ;
emitter . emitJavascript ( this . expr , TokenID . Identifier , false ) ;
}
else {
emitter . writeToOutput ( "default" ) ;
}
emitter . writeToOutput ( ":" ) ;
emitter . emitJavascriptStatements ( this . body , false , false ) ;
emitter . recordSourceMappingEnd ( this ) ;
emitter . emitParensAndCommentsInPlace ( this , false ) ;
} ;
CaseStatement . prototype . typeCheck = function ( typeFlow ) {
this . expr = typeFlow . typeCheck ( this . expr ) ;
typeFlow . typeCheck ( this . body ) ;
this . type = typeFlow . voidType ;
return this ;
} ;
// TODO: more reasoning about unreachable cases (such as duplicate literals as case expressions)
// for now, assume all cases are reachable, regardless of whether some cases fall through
CaseStatement . prototype . addToControlFlow = function ( context ) {
var execBlock = new BasicBlock ( ) ;
var sw = context . currentSwitch [ context . currentSwitch . length - 1 ] ;
// TODO: fall-through from previous (+ to end of switch)
if ( this . expr ) {
var exprBlock = new BasicBlock ( ) ;
context . current = exprBlock ;
sw . addSuccessor ( exprBlock ) ;
context . addContent ( this . expr ) ;
exprBlock . addSuccessor ( execBlock ) ;
}
else {
sw . addSuccessor ( execBlock ) ;
}
context . current = execBlock ;
if ( this . body ) {
context . walk ( this . body , this ) ;
}
context . noContinuation = false ;
context . walker . options . goChildren = false ;
} ;
return CaseStatement ;
} ) ( Statement ) ;
TypeScript . CaseStatement = CaseStatement ;
var TypeReference = ( function ( _super ) {
_ _extends ( TypeReference , _super ) ;
function TypeReference ( term , arrayCount ) {
_super . call ( this , NodeType . TypeRef ) ;
this . term = term ;
this . arrayCount = arrayCount ;
}
TypeReference . prototype . emit = function ( emitter , tokenId , startLine ) {
throw new Error ( "should not emit a type ref" ) ;
} ;
TypeReference . prototype . typeCheck = function ( typeFlow ) {
var prevInTCTR = typeFlow . inTypeRefTypeCheck ;
typeFlow . inTypeRefTypeCheck = true ;
var typeLink = getTypeLink ( this , typeFlow . checker , true ) ;
typeFlow . checker . resolveTypeLink ( typeFlow . scope , typeLink , false ) ;
if ( this . term ) {
typeFlow . typeCheck ( this . term ) ;
}
typeFlow . checkForVoidConstructor ( typeLink . type , this ) ;
this . type = typeLink . type ;
// in error recovery cases, there may not be a term
if ( this . term ) {
this . term . type = this . type ;
}
typeFlow . inTypeRefTypeCheck = prevInTCTR ;
return this ;
} ;
return TypeReference ;
} ) ( AST ) ;
TypeScript . TypeReference = TypeReference ;
var TryFinally = ( function ( _super ) {
_ _extends ( TryFinally , _super ) ;
function TryFinally ( tryNode , finallyNode ) {
_super . call ( this , NodeType . TryFinally ) ;
this . tryNode = tryNode ;
this . finallyNode = finallyNode ;
}
2015-02-07 05:03:24 +01:00
TryFinally . prototype . isCompoundStatement = function ( ) { return true ; } ;
2015-02-03 00:30:33 +01:00
TryFinally . prototype . emit = function ( emitter , tokenId , startLine ) {
emitter . recordSourceMappingStart ( this ) ;
emitter . emitJavascript ( this . tryNode , TokenID . Try , false ) ;
emitter . emitJavascript ( this . finallyNode , TokenID . Finally , false ) ;
emitter . recordSourceMappingEnd ( this ) ;
} ;
TryFinally . prototype . typeCheck = function ( typeFlow ) {
this . tryNode = typeFlow . typeCheck ( this . tryNode ) ;
this . finallyNode = typeFlow . typeCheck ( this . finallyNode ) ;
this . type = typeFlow . voidType ;
return this ;
} ;
TryFinally . prototype . addToControlFlow = function ( context ) {
var afterFinally = new BasicBlock ( ) ;
context . walk ( this . tryNode , this ) ;
var finBlock = new BasicBlock ( ) ;
if ( context . current ) {
context . current . addSuccessor ( finBlock ) ;
}
context . current = finBlock ;
context . pushStatement ( this , null , afterFinally ) ;
context . walk ( this . finallyNode , this ) ;
if ( ! context . noContinuation && context . current ) {
context . current . addSuccessor ( afterFinally ) ;
}
if ( afterFinally . predecessors . length > 0 ) {
context . current = afterFinally ;
}
else {
context . noContinuation = true ;
}
context . popStatement ( ) ;
context . walker . options . goChildren = false ;
} ;
return TryFinally ;
} ) ( Statement ) ;
TypeScript . TryFinally = TryFinally ;
var TryCatch = ( function ( _super ) {
_ _extends ( TryCatch , _super ) ;
function TryCatch ( tryNode , catchNode ) {
_super . call ( this , NodeType . TryCatch ) ;
this . tryNode = tryNode ;
this . catchNode = catchNode ;
}
2015-02-07 05:03:24 +01:00
TryCatch . prototype . isCompoundStatement = function ( ) { return true ; } ;
2015-02-03 00:30:33 +01:00
TryCatch . prototype . emit = function ( emitter , tokenId , startLine ) {
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . recordSourceMappingStart ( this ) ;
emitter . emitJavascript ( this . tryNode , TokenID . Try , false ) ;
emitter . emitJavascript ( this . catchNode , TokenID . Catch , false ) ;
emitter . recordSourceMappingEnd ( this ) ;
emitter . emitParensAndCommentsInPlace ( this , false ) ;
} ;
TryCatch . prototype . addToControlFlow = function ( context ) {
var beforeTry = context . current ;
var tryBlock = new BasicBlock ( ) ;
beforeTry . addSuccessor ( tryBlock ) ;
context . current = tryBlock ;
var afterTryCatch = new BasicBlock ( ) ;
context . pushStatement ( this , null , afterTryCatch ) ;
context . walk ( this . tryNode , this ) ;
if ( ! context . noContinuation ) {
if ( context . current ) {
context . current . addSuccessor ( afterTryCatch ) ;
}
}
context . current = new BasicBlock ( ) ;
beforeTry . addSuccessor ( context . current ) ;
context . walk ( this . catchNode , this ) ;
context . popStatement ( ) ;
if ( ! context . noContinuation ) {
if ( context . current ) {
context . current . addSuccessor ( afterTryCatch ) ;
}
}
context . current = afterTryCatch ;
context . walker . options . goChildren = false ;
} ;
TryCatch . prototype . typeCheck = function ( typeFlow ) {
this . tryNode = typeFlow . typeCheck ( this . tryNode ) ;
this . catchNode = typeFlow . typeCheck ( this . catchNode ) ;
this . type = typeFlow . voidType ;
return this ;
} ;
return TryCatch ;
} ) ( Statement ) ;
TypeScript . TryCatch = TryCatch ;
var Try = ( function ( _super ) {
_ _extends ( Try , _super ) ;
function Try ( body ) {
_super . call ( this , NodeType . Try ) ;
this . body = body ;
}
Try . prototype . emit = function ( emitter , tokenId , startLine ) {
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . recordSourceMappingStart ( this ) ;
emitter . writeToOutput ( "try " ) ;
emitter . emitJavascript ( this . body , TokenID . Try , false ) ;
emitter . recordSourceMappingEnd ( this ) ;
emitter . emitParensAndCommentsInPlace ( this , false ) ;
} ;
Try . prototype . typeCheck = function ( typeFlow ) {
this . body = typeFlow . typeCheck ( this . body ) ;
return this ;
} ;
Try . prototype . addToControlFlow = function ( context ) {
if ( this . body ) {
context . walk ( this . body , this ) ;
}
context . walker . options . goChildren = false ;
context . noContinuation = false ;
} ;
return Try ;
} ) ( Statement ) ;
TypeScript . Try = Try ;
var Catch = ( function ( _super ) {
_ _extends ( Catch , _super ) ;
function Catch ( param , body ) {
_super . call ( this , NodeType . Catch ) ;
this . param = param ;
this . body = body ;
this . statement = new ASTSpan ( ) ;
this . containedScope = null ;
if ( this . param ) {
this . param . varFlags |= VarFlags . AutoInit ;
}
}
Catch . prototype . emit = function ( emitter , tokenId , startLine ) {
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . recordSourceMappingStart ( this ) ;
emitter . writeToOutput ( " " ) ;
emitter . recordSourceMappingStart ( this . statement ) ;
emitter . writeToOutput ( "catch (" ) ;
emitter . emitJavascript ( this . param , TokenID . OpenParen , false ) ;
emitter . writeToOutput ( ")" ) ;
emitter . recordSourceMappingEnd ( this . statement ) ;
emitter . emitJavascript ( this . body , TokenID . Catch , false ) ;
emitter . recordSourceMappingEnd ( this ) ;
emitter . emitParensAndCommentsInPlace ( this , false ) ;
} ;
Catch . prototype . addToControlFlow = function ( context ) {
if ( this . param ) {
context . addContent ( this . param ) ;
var bodBlock = new BasicBlock ( ) ;
context . current . addSuccessor ( bodBlock ) ;
context . current = bodBlock ;
}
if ( this . body ) {
context . walk ( this . body , this ) ;
}
context . noContinuation = false ;
context . walker . options . goChildren = false ;
} ;
Catch . prototype . typeCheck = function ( typeFlow ) {
var prevScope = typeFlow . scope ;
typeFlow . scope = this . containedScope ;
this . param = typeFlow . typeCheck ( this . param ) ;
var exceptVar = new ValueLocation ( ) ;
var varSym = new VariableSymbol ( this . param . id . text , this . param . minChar , typeFlow . checker . locationInfo . unitIndex , exceptVar ) ;
exceptVar . symbol = varSym ;
exceptVar . typeLink = new TypeLink ( ) ;
// var type for now (add syntax for type annotation)
exceptVar . typeLink . type = typeFlow . anyType ;
var thisFnc = typeFlow . thisFnc ;
if ( thisFnc && thisFnc . type ) {
exceptVar . symbol . container = thisFnc . type . symbol ;
}
else {
exceptVar . symbol . container = null ;
}
this . param . sym = exceptVar . symbol ;
typeFlow . scope . enter ( exceptVar . symbol . container , this . param , exceptVar . symbol , typeFlow . checker . errorReporter , false , false , false ) ;
this . body = typeFlow . typeCheck ( this . body ) ;
// if we're in provisional typecheck mode, clean up the symbol entry
// REVIEW: This is obviously bad form, since we're counting on the internal
// layout of the symbol table, but this is also the only place where we insert
// symbols during typecheck
if ( typeFlow . checker . inProvisionalTypecheckMode ( ) ) {
var table = typeFlow . scope . getTable ( ) ;
table . secondaryTable . table [ exceptVar . symbol . name ] = undefined ;
}
this . type = typeFlow . voidType ;
typeFlow . scope = prevScope ;
return this ;
} ;
return Catch ;
} ) ( Statement ) ;
TypeScript . Catch = Catch ;
var Finally = ( function ( _super ) {
_ _extends ( Finally , _super ) ;
function Finally ( body ) {
_super . call ( this , NodeType . Finally ) ;
this . body = body ;
}
Finally . prototype . emit = function ( emitter , tokenId , startLine ) {
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . recordSourceMappingStart ( this ) ;
emitter . writeToOutput ( "finally" ) ;
emitter . emitJavascript ( this . body , TokenID . Finally , false ) ;
emitter . recordSourceMappingEnd ( this ) ;
emitter . emitParensAndCommentsInPlace ( this , false ) ;
} ;
Finally . prototype . addToControlFlow = function ( context ) {
if ( this . body ) {
context . walk ( this . body , this ) ;
}
context . walker . options . goChildren = false ;
context . noContinuation = false ;
} ;
Finally . prototype . typeCheck = function ( typeFlow ) {
this . body = typeFlow . typeCheck ( this . body ) ;
return this ;
} ;
return Finally ;
} ) ( Statement ) ;
TypeScript . Finally = Finally ;
var Comment = ( function ( _super ) {
_ _extends ( Comment , _super ) ;
function Comment ( content , isBlockComment , endsLine ) {
_super . call ( this , NodeType . Comment ) ;
this . content = content ;
this . isBlockComment = isBlockComment ;
this . endsLine = endsLine ;
this . text = null ;
}
Comment . prototype . getText = function ( ) {
if ( this . text == null ) {
if ( this . isBlockComment ) {
this . text = this . content . split ( "\n" ) ;
for ( var i = 0 ; i < this . text . length ; i ++ ) {
this . text [ i ] = this . text [ i ] . replace ( /^\s+|\s+$/g , '' ) ;
}
}
else {
this . text = [ ( this . content . replace ( /^\s+|\s+$/g , '' ) ) ] ;
}
}
return this . text ;
} ;
return Comment ;
} ) ( AST ) ;
TypeScript . Comment = Comment ;
var DebuggerStatement = ( function ( _super ) {
_ _extends ( DebuggerStatement , _super ) ;
function DebuggerStatement ( ) {
_super . call ( this , NodeType . Debugger ) ;
}
DebuggerStatement . prototype . emit = function ( emitter , tokenId , startLine ) {
emitter . emitParensAndCommentsInPlace ( this , true ) ;
emitter . recordSourceMappingStart ( this ) ;
emitter . writeLineToOutput ( "debugger;" ) ;
emitter . recordSourceMappingEnd ( this ) ;
emitter . emitParensAndCommentsInPlace ( this , false ) ;
} ;
return DebuggerStatement ;
} ) ( Statement ) ;
TypeScript . DebuggerStatement = DebuggerStatement ;
} ) ( TypeScript || ( TypeScript = { } ) ) ;