From 91d31c7f51223936d75fa429bb8d79de15dd458e Mon Sep 17 00:00:00 2001 From: Jason Freeman Date: Thu, 17 Jul 2014 19:11:01 -0700 Subject: [PATCH] Add error about missing module flag to createProgram --- src/compiler/binder.ts | 4 ++-- src/compiler/checker.ts | 18 ++++++++-------- src/compiler/emitter.ts | 8 +++---- src/compiler/parser.ts | 46 ++++++++++++++++++++++++++++++++--------- src/compiler/types.ts | 6 ++++-- 5 files changed, 55 insertions(+), 27 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 7f83681a490..d5b3a91eab2 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -168,7 +168,7 @@ module ts { declareModuleMember(node, symbolKind, symbolExcludes); break; case SyntaxKind.SourceFile: - if (container.flags & NodeFlags.ExternalModule) { + if (isExternalModule(container)) { declareModuleMember(node, symbolKind, symbolExcludes); break; } @@ -323,7 +323,7 @@ module ts { bindDeclaration(node, SymbolFlags.Import, SymbolFlags.ImportExcludes); break; case SyntaxKind.SourceFile: - if (node.flags & NodeFlags.ExternalModule) { + if (isExternalModule(node)) { bindAnonymousDeclaration(node, SymbolFlags.ValueModule, '"' + getModuleNameFromFilename((node).filename) + '"'); break; } diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 27ae96ed080..52eeb1d6c1c 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -183,7 +183,7 @@ module ts { } function isGlobalSourceFile(node: Node) { - return node.kind === SyntaxKind.SourceFile && !(node.flags & NodeFlags.ExternalModule); + return node.kind === SyntaxKind.SourceFile && !isExternalModule(node); } function getSymbol(symbols: SymbolTable, name: string, meaning: SymbolFlags): Symbol { @@ -238,7 +238,7 @@ module ts { } switch (location.kind) { case SyntaxKind.SourceFile: - if (!(location.flags & NodeFlags.ExternalModule)) break; + if (!isExternalModule(location)) break; case SyntaxKind.ModuleDeclaration: if (result = getSymbol(getSymbolOfNode(location).exports, name, meaning & SymbolFlags.ModuleMember)) { return returnResolvedSymbol(result); @@ -610,7 +610,7 @@ module ts { } switch (location.kind) { case SyntaxKind.SourceFile: - if (!(location.flags & NodeFlags.ExternalModule)) { + if (!isExternalModule(location)) { break; } case SyntaxKind.ModuleDeclaration: @@ -942,7 +942,7 @@ module ts { } } else if (node.kind === SyntaxKind.SourceFile) { - return (node.flags & NodeFlags.ExternalModule) ? node : undefined; + return isExternalModule(node) ? node : undefined; } } Debug.fail("getContainingModule cant reach here"); @@ -5799,7 +5799,7 @@ module ts { emitExtends = false; potentialThisCollisions.length = 0; forEach(node.statements, checkSourceElement); - if (node.flags & NodeFlags.ExternalModule) { + if (isExternalModule(node)) { var symbol = getExportAssignmentSymbol(node.symbol); if (symbol && symbol.flags & SymbolFlags.Import) { // Mark the import as referenced so that we emit it in the final .js file. @@ -5883,7 +5883,7 @@ module ts { } switch (location.kind) { case SyntaxKind.SourceFile: - if (!(location.flags & NodeFlags.ExternalModule)) break; + if (!isExternalModule(location)) break; case SyntaxKind.ModuleDeclaration: copySymbols(getSymbolOfNode(location).exports, meaning & SymbolFlags.ModuleMember); break; @@ -6036,7 +6036,7 @@ module ts { return getSourceTextOfNode(node.name); } - function isExternalModule(symbol: Symbol): boolean { + function isExternalModuleSymbol(symbol: Symbol): boolean { return symbol.flags & SymbolFlags.ValueModule && symbol.declarations.length === 1 && symbol.declarations[0].kind === SyntaxKind.SourceFile; } @@ -6057,7 +6057,7 @@ module ts { // symbol will have a parent if it is an export symbol if (symbol.parent) { - return isExternalModule(symbol.parent) ? "exports" : symbolToString(symbol.parent); + return isExternalModuleSymbol(symbol.parent) ? "exports" : symbolToString(symbol.parent); } } } @@ -6170,7 +6170,7 @@ module ts { }); // Initialize global symbol table forEach(program.getSourceFiles(), file => { - if (!(file.flags & NodeFlags.ExternalModule)) { + if (!isExternalModule(file)) { extendSymbolTable(globals, file.locals); } }); diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 5642decf273..0d056c0375e 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -31,7 +31,7 @@ module ts { function shouldEmitToOwnFile(sourceFile: SourceFile) { if (!(sourceFile.flags & NodeFlags.DeclarationFile)) { - if ((sourceFile.flags & NodeFlags.ExternalModule || !compilerOptions.out) && !fileExtensionIs(sourceFile.filename, ".js")) { + if ((isExternalModule(sourceFile) || !compilerOptions.out) && !fileExtensionIs(sourceFile.filename, ".js")) { return true; } } @@ -49,7 +49,7 @@ module ts { } function isExternalModuleOrDeclarationFile(sourceFile: SourceFile) { - return !!(sourceFile.flags & (NodeFlags.ExternalModule | NodeFlags.DeclarationFile)); + return isExternalModule(sourceFile) || (sourceFile.flags & NodeFlags.DeclarationFile) !== 0; } function getFirstConstructorWithBody(node: ClassDeclaration): ConstructorDeclaration { @@ -1552,7 +1552,7 @@ module ts { // preserve old compiler's behavior: emit 'var' for import declaration (even if we do not consider them referenced) when // - current file is not external module // - import declaration is top level and target is value imported by entity name - emitImportDeclaration = !(currentSourceFile.flags & NodeFlags.ExternalModule) && resolver.isTopLevelValueImportedViaEntityName(node); + emitImportDeclaration = !isExternalModule(currentSourceFile) && resolver.isTopLevelValueImportedViaEntityName(node); } if (emitImportDeclaration) { @@ -1701,7 +1701,7 @@ module ts { write("};"); extendsEmitted = true; } - if (node.flags & NodeFlags.ExternalModule) { + if (isExternalModule(node)) { if (compilerOptions.module === ModuleKind.AMD) { emitAMDModule(node, startIndex); } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 09f01af0c21..01de2b525a0 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -85,6 +85,19 @@ module ts { return flattenDiagnosticChain(file, start, length, messageChain); } + export function getErrorSpanForNode(node: Node): TextRange { + var errorSpan: TextRange; + switch (node.kind) { + // This list is a work in progress. Add missing node kinds to improve their error + // spans. + } + return errorSpan && errorSpan.pos < errorSpan.end ? errorSpan : node; + } + + export function isExternalModule(file: SourceFile): boolean { + return file.externalModuleIndicator !== undefined; + } + // Invokes a callback for each child of the given node. The 'cbNode' callback is invoked for all child nodes // stored in properties. If a 'cbNodes' callback is specified, it is invoked for embedded arrays; otherwise, // embedded arrays are flattened and the 'cbNode' callback is invoked for each element. If a callback returns @@ -377,8 +390,9 @@ module ts { // words, this function is called once we have already parsed the node, and are just // applying some stricter checks on that node. function grammarErrorOnNode(node: Node, message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any): void { - var start = skipTrivia(file.text, node.pos); - var length = node.end - start; + var span = getErrorSpanForNode(node); + var start = skipTrivia(file.text, span.pos); + var length = span.end - start; file.syntacticErrors.push(createFileDiagnostic(file, start, length, message, arg0, arg1, arg2)); } @@ -1838,8 +1852,8 @@ module ts { return makeFunctionExpression(SyntaxKind.FunctionExpression, pos, name, sig, body); } - function makeFunctionExpression(kind: SyntaxKind, pos: number, name: Identifier, sig: ParsedSignature, body: Node) { - var node = createNode(kind, pos); + function makeFunctionExpression(kind: SyntaxKind, pos: number, name: Identifier, sig: ParsedSignature, body: Node): FunctionExpression { + var node = createNode(kind, pos); node.name = name; node.typeParameters = sig.typeParameters; node.parameters = sig.parameters; @@ -2939,10 +2953,13 @@ module ts { }; } - function isExternalModule() { - return forEach(file.statements, node => node.flags & NodeFlags.Export || - node.kind === SyntaxKind.ImportDeclaration && (node).externalModuleName || - node.kind === SyntaxKind.ExportAssignment ? true : false); + function getExternalModuleIndicator() { + return forEach(file.statements, node => + node.flags & NodeFlags.Export + || node.kind === SyntaxKind.ImportDeclaration && (node).externalModuleName + || node.kind === SyntaxKind.ExportAssignment + ? node + : undefined); } scanner = createScanner(languageVersion, sourceText, scanError, onComment); @@ -2961,7 +2978,7 @@ module ts { file.referencedFiles = referenceComments.referencedFiles; file.amdDependencies = referenceComments.amdDependencies; file.statements = parseList(ParsingContext.SourceElements, parseSourceElement); - if (isExternalModule()) file.flags |= NodeFlags.ExternalModule; + file.externalModuleIndicator = getExternalModuleIndicator(); file.nodeCount = nodeCount; file.identifierCount = identifierCount; return file; @@ -3130,12 +3147,21 @@ module ts { return; } + var firstExternalModule = forEach(files, f => isExternalModule(f) ? f : undefined); + if (firstExternalModule && options.module === ModuleKind.None) { + // We cannot use createDiagnosticFromNode because nodes do not have parents yet + var externalModuleIndicatorNode = firstExternalModule.externalModuleIndicator; + var errorStart = skipTrivia(firstExternalModule.text, externalModuleIndicatorNode.pos); + var errorLength = externalModuleIndicatorNode.end - errorStart; + errors.push(createFileDiagnostic(firstExternalModule, errorStart, errorLength, Diagnostics.Cannot_compile_external_modules_unless_the_module_flag_is_provided)); + } + // there has to be common source directory if user specified --outdir || --sourcRoot // if user specified --mapRoot, there needs to be common source directory if there would be multiple files being emitted if (options.outDir || // there is --outDir specified options.sourceRoot || // there is --sourceRoot specified (options.mapRoot && // there is --mapRoot Specified and there would be multiple js files generated - (!options.out || !!filter(files, sourceFile => !!(sourceFile.flags & NodeFlags.ExternalModule)).length))) { + (!options.out || firstExternalModule !== undefined))) { var commonPathComponents: string[]; forEach(files, sourceFile => { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 65ca7d01fbd..b17e64dcd4d 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -229,7 +229,6 @@ module ts { MultiLine = 0x00000080, // Multi-line array or object literal Synthetic = 0x00000100, // Synthetic node (for full fidelity) DeclarationFile = 0x00000200, // Node is a .d.ts file - ExternalModule = 0x00000400, // Node is an external module Modifier = Export | Ambient | Public | Private | Static } @@ -336,7 +335,9 @@ module ts { whenFalse: Expression; } - export interface FunctionExpression extends Expression, FunctionDeclaration { } + export interface FunctionExpression extends Expression, FunctionDeclaration { + body: Node; // Required, whereas the member inherited from FunctionDeclaration is optional + } // The text property of a LiteralExpression stores the interpreted value of the literal in text form. For a StringLiteral // this means quotes have been removed and escapes have been converted to actual characters. For a NumericLiteral, the @@ -514,6 +515,7 @@ module ts { syntacticErrors: Diagnostic[]; semanticErrors: Diagnostic[]; hasNoDefaultLib: boolean; + externalModuleIndicator: Node; // The first node that causes this file to be an external module nodeCount: number; identifierCount: number; symbolCount: number;