namespace ts . pxtc { param program param entryPoint param compileTarget export function annotate ( program , entryPoint , compileTarget ) { const oldTarget = pxtc . target ; pxtc . target = compileTarget ; let src = program . getSourceFiles ( ) . filter ( f => f . fileName === entryPoint ) [ 0 ] ; let checker = program . getTypeChecker ( ) ; recurse ( src ) ; pxtc . target = oldTarget ; function recurse ( parent ) { ts . forEachChild ( parent , child => { switch ( child . kind ) { case SyntaxKind . CallExpression : mkCallInfo ( child , ( child as ts . CallExpression ) . arguments . slice ( 0 ) , null , getDecl ( ( child as ts . CallExpression ) . expression ) ) ; break ; case SyntaxKind . PropertyAccessExpression : mkCallInfo ( child , [ ] ) ; break ; case SyntaxKind . TaggedTemplateExpression : mkCallInfo ( child , [ ( child as ts . TaggedTemplateExpression ) . template ] , true , getDecl ( ( child as ts . TaggedTemplateExpression ) . tag ) ) ; break ; case SyntaxKind . BinaryExpression : annotateBinaryExpression ( child as ts . BinaryExpression ) ; break ; case SyntaxKind . Identifier : const decl = getDecl ( child ) ; if ( decl && decl . getSourceFile ( ) . fileName !== pxt . MAIN_TS && decl . kind == SyntaxKind . VariableDeclaration ) { const info = pxtInfo ( child ) ; info . flags |= PxtNodeFlags . IsGlobalIdentifier ; if ( ! info . commentAttrs ) { info . commentAttrs = parseComments ( decl ) ; } } break ; } recurse ( child ) ; } ) ; } function annotateBinaryExpression ( node ) { const trg = node . left ; const expr = node . right ; let lt = typeOf ( node . left ) ; let rt = typeOf ( node . right ) ; if ( node . operatorToken . kind == SK . PlusToken || node . operatorToken . kind == SK . PlusEqualsToken ) { if ( isStringType ( lt ) || ( isStringType ( rt ) && node . operatorToken . kind == SK . PlusToken ) ) { pxtInfo ( node ) . exprInfo = { leftType : checker . typeToString ( lt ) , rightType : checker . typeToString ( rt ) } ; } } switch ( node . operatorToken . kind ) { case SyntaxKind . EqualsToken : case SyntaxKind . PlusEqualsToken : case SyntaxKind . MinusEqualsToken : if ( trg . kind == SK . PropertyAccessExpression ) { let decl = getDecl ( trg ) ; if ( decl && decl . kind == SK . GetAccessor ) { decl = getDeclarationOfKind ( decl . symbol , SK . SetAccessor ) ; mkCallInfo ( trg , [ expr ] , false , decl ) ; } else if ( decl && ( decl . kind == SK . PropertySignature || decl . kind == SK . PropertyAssignment || ( target && target . switches . slowFields ) ) ) { mkCallInfo ( trg , [ expr ] ) ; } } break ; } } function mkCallInfo ( node , args , isExpression = false , d = null ) { let hasRet = isExpression || ! ( typeOf ( node ) . flags & TypeFlags . Void ) ; let decl = d || getDecl ( node ) ; if ( ( node as any ) . expression && decl ) { let isMethod = false ; switch ( decl . kind ) { case SK . PropertySignature : case SK . PropertyAssignment : case SK . PropertyDeclaration : if ( ! isStatic ( decl ) ) { isMethod = true ; } break ; case SK . Parameter : if ( isCtorField ( decl as ParameterDeclaration ) ) { isMethod = true ; } break ; case SK . GetAccessor : case SK . SetAccessor : case SK . MethodDeclaration : case SK . MethodSignature : isMethod = true ; break ; default : break ; } if ( isMethod ) { const expr = ( node as any ) . expression ; if ( expr . kind === SK . PropertyAccessExpression ) { args . unshift ( ( expr as PropertyAccessExpression ) . expression ) ; } else { args . unshift ( ( node as any ) . expression ) ; } } } let callInfo = { decl , qName : decl ? getNodeFullName ( checker , decl ) : "?" , args : args , isExpression : hasRet } ; pxtInfo ( node ) . callInfo = callInfo ; } function getDecl ( node ) { if ( ! node ) return null ; let sym = checker . getSymbolAtLocation ( node ) ; let decl ; if ( sym ) { decl = sym . valueDeclaration ; if ( ! decl && sym . declarations ) { let decl0 = sym . declarations [ 0 ] ; if ( decl0 && decl0 . kind == SyntaxKind . ImportEqualsDeclaration ) { sym = checker . getSymbolAtLocation ( ( decl0 as ImportEqualsDeclaration ) . moduleReference ) ; if ( sym ) decl = sym . valueDeclaration ; } } } if ( ! decl && node . kind == SK . PropertyAccessExpression ) { const namedNode = node as PropertyAccessExpression ; decl = { kind : SK . PropertySignature , symbol : { isBogusSymbol : true , name : namedNode . name . getText ( ) } , name : namedNode . name , } as any ; pxtInfo ( decl ) . flags |= PxtNodeFlags . IsBogusFunction ; } return decl ; } function typeOf ( node ) { let r ; const info = pxtInfo ( node ) ; if ( info . typeCache ) return info . typeCache ; if ( isExpression ( node ) ) r = checker . getContextualType ( < Expression > node ) ; if ( ! r ) { r = checker . getTypeAtLocation ( node ) ; } if ( ! r ) return r ; if ( isStringLiteral ( node ) ) return r ; return checkType ( r ) ; } } }