From f8dd19ed1ca73fc64ff1e4039fd18584de827435 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 12 Dec 2014 12:01:27 -0800 Subject: [PATCH 1/3] Resurrect the post edit invariants checking for fourslash. --- src/harness/fourslash.ts | 60 +++++++++++++++++------------------- src/harness/harness.ts | 14 +++++++++ src/harness/test262Runner.ts | 15 +-------- 3 files changed, 44 insertions(+), 45 deletions(-) diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index e253f7b575b..12a538126f1 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -1415,44 +1415,42 @@ module FourSlash { } private checkPostEditInvariants() { - return; + if (this.editValidation === IncrementalEditValidation.None) { + return; + } - /// TODO: reimplement this section - //if (this.editValidation === IncrementalEditValidation.None) { - // return; - //} + // Get syntactic errors (to force a refresh) + var incrSyntaxErrs = JSON.stringify(Utils.convertDiagnostics(this.languageService.getSyntacticDiagnostics(this.activeFile.fileName))); - //// Get syntactic errors (to force a refresh) - //var incrSyntaxErrs = JSON.stringify(this.languageService.getSyntacticDiagnostics(this.activeFile.fileName)); + // Check syntactic structure + var snapshot = this.languageServiceShimHost.getScriptSnapshot(this.activeFile.fileName); + var content = snapshot.getText(0, snapshot.getLength()); + var refSyntaxTree = ts.createLanguageServiceSourceFile( + this.activeFile.fileName, createScriptSnapShot(content), ts.ScriptTarget.Latest, /*version:*/ "0", /*isOpen:*/ false, /*setNodeParents:*/ false); + var fullSyntaxErrs = JSON.stringify(Utils.convertDiagnostics(refSyntaxTree.getSyntacticDiagnostics())); - //// Check syntactic structure - //var snapshot = this.languageServiceShimHost.getScriptSnapshot(this.activeFile.fileName); - //var content = snapshot.getText(0, snapshot.getLength()); - //var refSyntaxTree = TypeScript.Parser.parse(this.activeFile.fileName, TypeScript.SimpleText.fromString(content), ts.ScriptTarget.ES5, TypeScript.isDTSFile(this.activeFile.fileName)); - //var fullSyntaxErrs = JSON.stringify(refSyntaxTree.diagnostics()); + if (incrSyntaxErrs !== fullSyntaxErrs) { + this.raiseError('Mismatched incremental/full syntactic errors for file ' + this.activeFile.fileName + '.\n=== Incremental errors ===\n' + incrSyntaxErrs + '\n=== Full Errors ===\n' + fullSyntaxErrs); + } - //if (incrSyntaxErrs !== fullSyntaxErrs) { - // this.raiseError('Mismatched incremental/full syntactic errors for file ' + this.activeFile.fileName + '.\n=== Incremental errors ===\n' + incrSyntaxErrs + '\n=== Full Errors ===\n' + fullSyntaxErrs); - //} + //if (this.editValidation !== IncrementalEditValidation.SyntacticOnly) { + // var compiler = new TypeScript.TypeScriptCompiler(); + // for (var i = 0; i < this.testData.files.length; i++) { + // snapshot = this.languageServiceShimHost.getScriptSnapshot(this.testData.files[i].fileName); + // compiler.addFile(this.testData.files[i].fileName, TypeScript.ScriptSnapshot.fromString(snapshot.getText(0, snapshot.getLength())), ts.ByteOrderMark.None, 0, true); + // } - // if (this.editValidation !== IncrementalEditValidation.SyntacticOnly) { - // var compiler = new TypeScript.TypeScriptCompiler(); - // for (var i = 0; i < this.testData.files.length; i++) { - // snapshot = this.languageServiceShimHost.getScriptSnapshot(this.testData.files[i].fileName); - // compiler.addFile(this.testData.files[i].fileName, TypeScript.ScriptSnapshot.fromString(snapshot.getText(0, snapshot.getLength())), ts.ByteOrderMark.None, 0, true); - // } + // compiler.addFile('lib.d.ts', TypeScript.ScriptSnapshot.fromString(Harness.Compiler.libTextMinimal), ts.ByteOrderMark.None, 0, true); - // compiler.addFile('lib.d.ts', TypeScript.ScriptSnapshot.fromString(Harness.Compiler.libTextMinimal), ts.ByteOrderMark.None, 0, true); + // for (var i = 0; i < this.testData.files.length; i++) { + // var refSemanticErrs = JSON.stringify(compiler.getSemanticDiagnostics(this.testData.files[i].fileName)); + // var incrSemanticErrs = JSON.stringify(this.languageService.getSemanticDiagnostics(this.testData.files[i].fileName)); - // for (var i = 0; i < this.testData.files.length; i++) { - // var refSemanticErrs = JSON.stringify(compiler.getSemanticDiagnostics(this.testData.files[i].fileName)); - // var incrSemanticErrs = JSON.stringify(this.languageService.getSemanticDiagnostics(this.testData.files[i].fileName)); - - // if (incrSemanticErrs !== refSemanticErrs) { - // this.raiseError('Mismatched incremental/full semantic errors for file ' + this.testData.files[i].fileName + '\n=== Incremental errors ===\n' + incrSemanticErrs + '\n=== Full Errors ===\n' + refSemanticErrs); - // } - // } - // } + // if (incrSemanticErrs !== refSemanticErrs) { + // this.raiseError('Mismatched incremental/full semantic errors for file ' + this.testData.files[i].fileName + '\n=== Incremental errors ===\n' + incrSemanticErrs + '\n=== Full Errors ===\n' + refSemanticErrs); + // } + // } + //} } private fixCaretPosition() { diff --git a/src/harness/harness.ts b/src/harness/harness.ts index 5a4837949a5..095b0702b12 100644 --- a/src/harness/harness.ts +++ b/src/harness/harness.ts @@ -175,6 +175,20 @@ module Utils { function isNodeOrArray(a: any): boolean { return a !== undefined && typeof a.pos === "number"; } + + export function convertDiagnostics(diagnostics: ts.Diagnostic[]) { + return diagnostics.map(convertDiagnostic); + } + + function convertDiagnostic(diagnostic: ts.Diagnostic) { + return { + start: diagnostic.start, + length: diagnostic.length, + messageText: diagnostic.messageText, + category: (ts).DiagnosticCategory[diagnostic.category], + code: diagnostic.code + }; + } } module Harness.Path { diff --git a/src/harness/test262Runner.ts b/src/harness/test262Runner.ts index 8c39880a81c..f6ba448015b 100644 --- a/src/harness/test262Runner.ts +++ b/src/harness/test262Runner.ts @@ -52,19 +52,6 @@ class Test262BaselineRunner extends RunnerBase { function getNodeFlagName(f: number) { return getFlagName((ts).NodeFlags, f); } function getParserContextFlagName(f: number) { return getFlagName((ts).ParserContextFlags, f); } - function convertDiagnostics(diagnostics: ts.Diagnostic[]) { - return diagnostics.map(convertDiagnostic); - } - - function convertDiagnostic(diagnostic: ts.Diagnostic): any { - return { - start: diagnostic.start, - length: diagnostic.length, - messageText: diagnostic.messageText, - category: (ts).DiagnosticCategory[diagnostic.category], - code: diagnostic.code - }; - } function serializeNode(n: ts.Node): any { var o: any = { kind: getKindName(n.kind) }; @@ -97,7 +84,7 @@ class Test262BaselineRunner extends RunnerBase { case "referenceDiagnostics": case "parseDiagnostics": case "grammarDiagnostics": - o[propertyName] = convertDiagnostics((n)[propertyName]); + o[propertyName] = Utils.convertDiagnostics((n)[propertyName]); break; case "nextContainer": From 0aa3f6e607d56e51d80e1945971f79456765c899 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 12 Dec 2014 13:09:50 -0800 Subject: [PATCH 2/3] Rename some locals. --- src/harness/fourslash.ts | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index 12a538126f1..7f5f3688817 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -1419,18 +1419,19 @@ module FourSlash { return; } - // Get syntactic errors (to force a refresh) - var incrSyntaxErrs = JSON.stringify(Utils.convertDiagnostics(this.languageService.getSyntacticDiagnostics(this.activeFile.fileName))); + var incrementalSourceFile = this.languageService.getSourceFile(this.activeFile.fileName); + var incrementalSyntaxDiagnostics = JSON.stringify(Utils.convertDiagnostics(incrementalSourceFile.getSyntacticDiagnostics())); // Check syntactic structure var snapshot = this.languageServiceShimHost.getScriptSnapshot(this.activeFile.fileName); var content = snapshot.getText(0, snapshot.getLength()); - var refSyntaxTree = ts.createLanguageServiceSourceFile( - this.activeFile.fileName, createScriptSnapShot(content), ts.ScriptTarget.Latest, /*version:*/ "0", /*isOpen:*/ false, /*setNodeParents:*/ false); - var fullSyntaxErrs = JSON.stringify(Utils.convertDiagnostics(refSyntaxTree.getSyntacticDiagnostics())); - if (incrSyntaxErrs !== fullSyntaxErrs) { - this.raiseError('Mismatched incremental/full syntactic errors for file ' + this.activeFile.fileName + '.\n=== Incremental errors ===\n' + incrSyntaxErrs + '\n=== Full Errors ===\n' + fullSyntaxErrs); + var referenceSourceFile = ts.createLanguageServiceSourceFile( + this.activeFile.fileName, createScriptSnapShot(content), ts.ScriptTarget.Latest, /*version:*/ "0", /*isOpen:*/ false, /*setNodeParents:*/ false); + var referenceSyntaxDiagnostics = JSON.stringify(Utils.convertDiagnostics(referenceSourceFile.getSyntacticDiagnostics())); + + if (incrementalSyntaxDiagnostics !== referenceSyntaxDiagnostics) { + this.raiseError('Mismatched incremental/reference syntactic diagnostics for file ' + this.activeFile.fileName + '.\n=== Incremental diagnostics ===\n' + incrementalSyntaxDiagnostics + '\n=== Reference Diagnostics ===\n' + referenceSyntaxDiagnostics); } //if (this.editValidation !== IncrementalEditValidation.SyntacticOnly) { From f6aaa841468cc166f8f5483b0a39820ee661706e Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Fri, 12 Dec 2014 13:26:43 -0800 Subject: [PATCH 3/3] In Fourslash: Compare ASTs for files produced incrementally versus files produced with a full parse. --- src/harness/fourslash.ts | 7 +++ src/harness/harness.ts | 95 +++++++++++++++++++++++++++++++++ src/harness/test262Runner.ts | 100 +---------------------------------- 3 files changed, 103 insertions(+), 99 deletions(-) diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index 7f5f3688817..18d34e94b03 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -1434,6 +1434,13 @@ module FourSlash { this.raiseError('Mismatched incremental/reference syntactic diagnostics for file ' + this.activeFile.fileName + '.\n=== Incremental diagnostics ===\n' + incrementalSyntaxDiagnostics + '\n=== Reference Diagnostics ===\n' + referenceSyntaxDiagnostics); } + var incrementalSourceFileJSON = Utils.sourceFileToJSON(incrementalSourceFile); + var referenceSourceFileJSON = Utils.sourceFileToJSON(referenceSourceFile); + + if (incrementalSyntaxDiagnostics !== referenceSyntaxDiagnostics) { + this.raiseError('Mismatched incremental/reference ast for file ' + this.activeFile.fileName + '.\n=== Incremental AST ===\n' + incrementalSourceFileJSON + '\n=== Reference AST ===\n' + referenceSourceFileJSON); + } + //if (this.editValidation !== IncrementalEditValidation.SyntacticOnly) { // var compiler = new TypeScript.TypeScriptCompiler(); // for (var i = 0; i < this.testData.files.length; i++) { diff --git a/src/harness/harness.ts b/src/harness/harness.ts index 095b0702b12..61e5fcbee65 100644 --- a/src/harness/harness.ts +++ b/src/harness/harness.ts @@ -189,6 +189,101 @@ module Utils { code: diagnostic.code }; } + + export function sourceFileToJSON(file: ts.SourceFile): string { + return JSON.stringify(file,(k, v) => { + return isNodeOrArray(v) ? serializeNode(v) : v; + }, " "); + + function getKindName(k: number): string { + return (ts).SyntaxKind[k] + } + + function getFlagName(flags: any, f: number): any { + if (f === 0) { + return 0; + } + + var result = ""; + ts.forEach(Object.getOwnPropertyNames(flags),(v: any) => { + if (isFinite(v)) { + v = +v; + if (f === +v) { + result = flags[v]; + return true; + } + else if ((f & v) > 0) { + if (result.length) + result += " | "; + result += flags[v]; + return false; + } + } + }); + return result; + } + + function getNodeFlagName(f: number) { return getFlagName((ts).NodeFlags, f); } + function getParserContextFlagName(f: number) { return getFlagName((ts).ParserContextFlags, f); } + + function serializeNode(n: ts.Node): any { + var o: any = { kind: getKindName(n.kind) }; + o.containsParseError = ts.containsParseError(n); + + ts.forEach(Object.getOwnPropertyNames(n), propertyName => { + switch (propertyName) { + case "parent": + case "symbol": + case "locals": + case "localSymbol": + case "kind": + case "semanticDiagnostics": + case "id": + case "nodeCount": + case "symbolCount": + case "identifierCount": + case "scriptSnapshot": + // Blacklist of items we never put in the baseline file. + break; + + case "flags": + // Print out flags with their enum names. + o[propertyName] = getNodeFlagName(n.flags); + break; + + case "parserContextFlags": + o[propertyName] = getParserContextFlagName(n.parserContextFlags); + break; + + case "referenceDiagnostics": + case "parseDiagnostics": + case "grammarDiagnostics": + o[propertyName] = Utils.convertDiagnostics((n)[propertyName]); + break; + + case "nextContainer": + if (n.nextContainer) { + o[propertyName] = { kind: n.nextContainer.kind, pos: n.nextContainer.pos, end: n.nextContainer.end }; + } + break; + + case "text": + // Include 'text' field for identifiers/literals, but not for source files. + if (n.kind !== ts.SyntaxKind.SourceFile) { + o[propertyName] = (n)[propertyName]; + } + break; + + default: + o[propertyName] = (n)[propertyName]; + } + + return undefined; + }); + + return o; + } + } } module Harness.Path { diff --git a/src/harness/test262Runner.ts b/src/harness/test262Runner.ts index f6ba448015b..7e5bafde228 100644 --- a/src/harness/test262Runner.ts +++ b/src/harness/test262Runner.ts @@ -21,104 +21,6 @@ class Test262BaselineRunner extends RunnerBase { return Test262BaselineRunner.basePath + "/" + filename; } - private static serializeSourceFile(file: ts.SourceFile): string { - function getKindName(k: number): string { - return (ts).SyntaxKind[k] - } - - function getFlagName(flags: any, f: number): any { - if (f === 0) { - return 0; - } - - var result = ""; - ts.forEach(Object.getOwnPropertyNames(flags), (v: any) => { - if (isFinite(v)) { - v = +v; - if (f === +v) { - result = flags[v]; - return true; - } - else if ((f & v) > 0) { - if (result.length) - result += " | "; - result += flags[v]; - return false; - } - } - }); - return result; - } - - function getNodeFlagName(f: number) { return getFlagName((ts).NodeFlags, f); } - function getParserContextFlagName(f: number) { return getFlagName((ts).ParserContextFlags, f); } - - function serializeNode(n: ts.Node): any { - var o: any = { kind: getKindName(n.kind) }; - o.containsParseError = ts.containsParseError(n); - - ts.forEach(Object.getOwnPropertyNames(n), propertyName => { - switch (propertyName) { - case "parent": - case "symbol": - case "locals": - case "localSymbol": - case "kind": - case "semanticDiagnostics": - case "id": - case "nodeCount": - case "symbolCount": - case "identifierCount": - // Blacklist of items we never put in the baseline file. - break; - - case "flags": - // Print out flags with their enum names. - o[propertyName] = getNodeFlagName(n.flags); - break; - - case "parserContextFlags": - o[propertyName] = getParserContextFlagName(n.parserContextFlags); - break; - - case "referenceDiagnostics": - case "parseDiagnostics": - case "grammarDiagnostics": - o[propertyName] = Utils.convertDiagnostics((n)[propertyName]); - break; - - case "nextContainer": - if (n.nextContainer) { - o[propertyName] = { kind: n.nextContainer.kind, pos: n.nextContainer.pos, end: n.nextContainer.end }; - } - break; - - case "text": - // Include 'text' field for identifiers/literals, but not for source files. - if (n.kind !== ts.SyntaxKind.SourceFile) { - o[propertyName] = (n)[propertyName]; - } - break; - - default: - o[propertyName] = (n)[propertyName]; - } - - return undefined; - }); - - return o; - } - - return JSON.stringify(file, (k, v) => { - return Test262BaselineRunner.isNodeOrArray(v) ? serializeNode(v) : v; - }, " "); - } - - private static isNodeOrArray(a: any): boolean { - return a !== undefined && typeof a.pos === "number"; - } - private runTest(filePath: string) { describe('test262 test for ' + filePath, () => { // Mocha holds onto the closure environment of the describe callback even after the test is done. @@ -183,7 +85,7 @@ class Test262BaselineRunner extends RunnerBase { it('has the expected AST',() => { Harness.Baseline.runBaseline('has the expected AST', testState.filename + '.AST.txt',() => { var sourceFile = testState.checker.getProgram().getSourceFile(Test262BaselineRunner.getTestFilePath(testState.filename)); - return Test262BaselineRunner.serializeSourceFile(sourceFile); + return Utils.sourceFileToJSON(sourceFile); }, false, Test262BaselineRunner.baselineOptions); }); });