From 9dbdd7273fed27d41162affd74421ba0ace1abd5 Mon Sep 17 00:00:00 2001 From: dcode Date: Thu, 28 May 2020 23:39:01 +0200 Subject: [PATCH 1/3] Improve error message if an import cannot be found --- cli/asc.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/cli/asc.js b/cli/asc.js index 5a6a22dd7d..2215e823e3 100644 --- a/cli/asc.js +++ b/cli/asc.js @@ -534,7 +534,14 @@ exports.main = function main(argv, options, callback) { var internalPath; while ((internalPath = assemblyscript.nextFile(program)) != null) { let file = getFile(internalPath, assemblyscript.getDependee(program, internalPath)); - if (!file) return callback(Error("Import '" + internalPath + "' not found.")); + if (!file) { + const searchPaths = [ + path.join(baseDir, internalPath + ".ts"), + path.join(baseDir, internalPath, "index.ts"), + path.join(baseDir, internalPath + ".d.ts") + ]; + return callback(Error("Import '" + internalPath + "' not found.\n No such file '" + searchPaths.join("'\n No such file '") + "'")); + } stats.parseCount++; stats.parseTime += measure(() => { assemblyscript.parse(program, file.sourceText, file.sourcePath, false); From 24a53351cb700253f39dfe3ff445a85938881f54 Mon Sep 17 00:00:00 2001 From: dcode Date: Fri, 29 May 2020 06:43:30 +0200 Subject: [PATCH 2/3] honor file extension, refer to dependee --- cli/asc.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/cli/asc.js b/cli/asc.js index 2215e823e3..54bbe02372 100644 --- a/cli/asc.js +++ b/cli/asc.js @@ -533,14 +533,15 @@ exports.main = function main(argv, options, callback) { function parseBacklog() { var internalPath; while ((internalPath = assemblyscript.nextFile(program)) != null) { - let file = getFile(internalPath, assemblyscript.getDependee(program, internalPath)); + let dependee = assemblyscript.getDependee(program, internalPath); + let file = getFile(internalPath, dependee); if (!file) { const searchPaths = [ - path.join(baseDir, internalPath + ".ts"), - path.join(baseDir, internalPath, "index.ts"), - path.join(baseDir, internalPath + ".d.ts") + path.resolve(baseDir, internalPath + extension.ext), + path.resolve(baseDir, internalPath, "index" + extension.ext), + path.resolve(baseDir, internalPath + extension.ext_d) ]; - return callback(Error("Import '" + internalPath + "' not found.\n No such file '" + searchPaths.join("'\n No such file '") + "'")); + return callback(Error("Import path '" + internalPath + "' in '" + dependee + "' not found.\n No such file '" + searchPaths.join("'\n No such file '") + "'")); } stats.parseCount++; stats.parseTime += measure(() => { From d26253d1c0706b4ca9c21444695b02b4bcb5871c Mon Sep 17 00:00:00 2001 From: dcode Date: Fri, 29 May 2020 15:51:35 +0200 Subject: [PATCH 3/3] move error reporting to compiler --- cli/asc.js | 39 ++++++++++---------- src/index.ts | 4 +-- src/parser.ts | 59 +++++++++++++++++++++++-------- tests/packages/packages/g/test.js | 13 ++++--- 4 files changed, 71 insertions(+), 44 deletions(-) diff --git a/cli/asc.js b/cli/asc.js index 54bbe02372..9d718d8bd0 100644 --- a/cli/asc.js +++ b/cli/asc.js @@ -207,20 +207,20 @@ exports.main = function main(argv, options, callback) { // Check for unknown arguments if (opts.unknown.length) { opts.unknown.forEach(arg => { - stderr.write(colorsUtil.stderr.yellow("WARN: ") + "Unknown option '" + arg + "'" + EOL); + stderr.write(colorsUtil.stderr.yellow("WARNING ") + "Unknown option '" + arg + "'" + EOL); }); } // Check for trailing arguments if (opts.trailing.length) { - stderr.write(colorsUtil.stderr.yellow("WARN: ") + "Unsupported trailing arguments: " + opts.trailing.join(" ") + EOL); + stderr.write(colorsUtil.stderr.yellow("WARNING ") + "Unsupported trailing arguments: " + opts.trailing.join(" ") + EOL); } // Use default callback if none is provided if (!callback) callback = function defaultCallback(err) { var code = 0; if (err) { - stderr.write(colorsUtil.stderr.red("ERROR: ") + err.stack.replace(/^ERROR: /i, "") + EOL); + stderr.write(colorsUtil.stderr.red("FAILURE ") + err.stack.replace(/^ERROR: /i, "") + EOL); code = 1; } return code; @@ -533,24 +533,21 @@ exports.main = function main(argv, options, callback) { function parseBacklog() { var internalPath; while ((internalPath = assemblyscript.nextFile(program)) != null) { - let dependee = assemblyscript.getDependee(program, internalPath); - let file = getFile(internalPath, dependee); - if (!file) { - const searchPaths = [ - path.resolve(baseDir, internalPath + extension.ext), - path.resolve(baseDir, internalPath, "index" + extension.ext), - path.resolve(baseDir, internalPath + extension.ext_d) - ]; - return callback(Error("Import path '" + internalPath + "' in '" + dependee + "' not found.\n No such file '" + searchPaths.join("'\n No such file '") + "'")); + let file = getFile(internalPath, assemblyscript.getDependee(program, internalPath)); + if (file) { + stats.parseCount++; + stats.parseTime += measure(() => { + assemblyscript.parse(program, file.sourceText, file.sourcePath, false); + }); + } else { + assemblyscript.parse(program, null, internalPath + extension.ext, false); } - stats.parseCount++; - stats.parseTime += measure(() => { - assemblyscript.parse(program, file.sourceText, file.sourcePath, false); - }); } var numErrors = checkDiagnostics(program, stderr); if (numErrors) { - return callback(Error(numErrors + " parse error(s)")); + const err = Error(numErrors + " parse error(s)"); + err.stack = err.message; // omit stack + return callback(err); } } @@ -585,8 +582,8 @@ exports.main = function main(argv, options, callback) { let sourceText = readFile(sourcePath + extension.ext, baseDir); if (sourceText == null) { sourceText = readFile(sourcePath + "/index" + extension.ext, baseDir); - if (sourceText == null) return callback(Error("Entry file '" + sourcePath + extension.ext + "' not found.")); - sourcePath += "/index" + extension.ext; + if (sourceText != null) sourcePath += "/index" + extension.ext; + else sourcePath += extension.ext; } else { sourcePath += extension.ext; } @@ -642,7 +639,9 @@ exports.main = function main(argv, options, callback) { var numErrors = checkDiagnostics(program, stderr); if (numErrors) { if (module) module.dispose(); - return callback(Error(numErrors + " compile error(s)")); + const err = Error(numErrors + " compile error(s)"); + err.stack = err.message; // omit stack + return callback(err); } // Call afterCompile transform hook diff --git a/src/index.ts b/src/index.ts index 653ef77257..48cf27960f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -214,8 +214,8 @@ export function isError(message: DiagnosticMessage): bool { export function parse( /** Program reference. */ program: Program, - /** Source text of the file. */ - text: string, + /** Source text of the file, or `null` to indicate not found. */ + text: string | null, /** Normalized path of the file. */ path: string, /** Whether this is an entry file. */ diff --git a/src/parser.ts b/src/parser.ts index 6374660079..7c2dc90c8e 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -89,6 +89,14 @@ import { mangleInternalPath } from "./ast"; +/** Represents a dependee. */ +class Dependee { + constructor( + public source: Source, + public reportNode: Node + ) {} +} + /** Parser interface. */ export class Parser extends DiagnosticEmitter { @@ -102,8 +110,8 @@ export class Parser extends DiagnosticEmitter { onComment: CommentHandler | null = null; /** Current file being parsed. */ currentSource: Source | null = null; - /** Dependency map **/ - dependees: Map = new Map(); + /** Map of dependees being depended upon by a source, by path. */ + dependees: Map = new Map(); /** An array of parsed sources. */ sources: Source[]; @@ -118,8 +126,8 @@ export class Parser extends DiagnosticEmitter { /** Parses a file and adds its definitions to the program. */ parseFile( - /** Source text of the file. */ - text: string, + /** Source text of the file, or `null` to indicate not found. */ + text: string | null, /** Normalized path of the file. */ path: string, /** Whether this is an entry file. */ @@ -127,12 +135,28 @@ export class Parser extends DiagnosticEmitter { ): void { // the frontend gives us paths with file extensions var normalizedPath = normalizePath(path); - var internalPath = mangleInternalPath(normalizedPath); + var internalPath = mangleInternalPath(path); + // check if already processed if (this.donelog.has(internalPath)) return; this.donelog.add(internalPath); // do not parse again this.seenlog.add(internalPath); // do not request again + // check if this is an error + if (text === null) { + let dependees = this.dependees; + let dependee: Dependee | null = null; + if (dependees.has(internalPath)) dependee = assert(dependees.get(internalPath)); + this.error( + DiagnosticCode.File_0_not_found, + dependee + ? dependee.reportNode.range + : null, + path + ); + return; + } + // create the source element var source = new Source( isEntry @@ -402,10 +426,13 @@ export class Parser extends DiagnosticEmitter { return backlog.length ? assert(backlog.shift()) : null; } - /** Obtains the dependee of the given imported file. */ + /** Obtains the path of the dependee of the given imported file. */ getDependee(dependent: string): string | null { - var source = this.dependees.get(dependent); - if (source) return source.internalPath; + var dependees = this.dependees; + if (dependees.has(dependent)) { + let dependee = assert(dependees.get(dependent)); + return dependee.source.internalPath; + } return null; } @@ -2447,11 +2474,13 @@ export class Parser extends DiagnosticEmitter { } } let ret = Node.createExportStatement(members, path, isDeclare, tn.range(startPos, tn.pos)); - let internalPath = ret.internalPath; - if (internalPath !== null && !this.seenlog.has(internalPath)) { - this.dependees.set(internalPath, currentSource); - this.backlog.push(internalPath); - this.seenlog.add(internalPath); + if (path !== null) { + let internalPath = assert(ret.internalPath); + if (!this.seenlog.has(internalPath)) { + this.dependees.set(internalPath, new Dependee(currentSource, path)); + this.backlog.push(internalPath); + this.seenlog.add(internalPath); + } } tn.skip(Token.SEMICOLON); return ret; @@ -2466,7 +2495,7 @@ export class Parser extends DiagnosticEmitter { if (!exportPaths) source.exportPaths = [ internalPath ]; else if (!exportPaths.includes(internalPath)) exportPaths.push(internalPath); if (!this.seenlog.has(internalPath)) { - this.dependees.set(internalPath, currentSource); + this.dependees.set(internalPath, new Dependee(currentSource, path)); this.backlog.push(internalPath); } tn.skip(Token.SEMICOLON); @@ -2638,7 +2667,7 @@ export class Parser extends DiagnosticEmitter { } let internalPath = ret.internalPath; if (!this.seenlog.has(internalPath)) { - this.dependees.set(internalPath, assert(this.currentSource)); + this.dependees.set(internalPath, new Dependee(assert(this.currentSource), path)); this.backlog.push(internalPath); } tn.skip(Token.SEMICOLON); diff --git a/tests/packages/packages/g/test.js b/tests/packages/packages/g/test.js index 9d8d35b972..677082bdbb 100644 --- a/tests/packages/packages/g/test.js +++ b/tests/packages/packages/g/test.js @@ -1,17 +1,16 @@ #!/usr/bin/env node -let asc = require("../../../../cli/asc"); +const asc = require("../../../../cli/asc"); -let argv = [ +const stderr = asc.createMemoryStream(); +asc.main([ "assembly/index.ts", "--noEmit", "--runtime", "stub", "--traceResolution" -]; - -asc.main(argv, error => { - if (/Import .*lib\/a.* not found/g.test(error.message)) { +], { stderr }, err => { + if (stderr.toString().includes("File '~lib/a.ts' not found.")) { process.exit(0); } - console.error("Failed!\n" + error); + console.error("Failed!\n" + err); process.exit(1); });