diff --git a/cli/asc.js b/cli/asc.js index 5a6a22dd7d..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; @@ -534,15 +534,20 @@ 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.")); - stats.parseCount++; - stats.parseTime += measure(() => { - assemblyscript.parse(program, file.sourceText, file.sourcePath, false); - }); + if (file) { + stats.parseCount++; + stats.parseTime += measure(() => { + assemblyscript.parse(program, file.sourceText, file.sourcePath, false); + }); + } else { + assemblyscript.parse(program, null, internalPath + extension.ext, 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); } } @@ -577,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; } @@ -634,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); });