error recovery!

This commit is contained in:
nora 2023-08-06 00:07:10 +02:00
parent c0c08488ba
commit ef04f21100
18 changed files with 799 additions and 366 deletions

View file

@ -1,27 +1,41 @@
import { DepCrate } from "./ast";
import { CrateId, DepCrate } from "./ast";
import { CrateLoader, GlobalContext } from "./context";
import { CompilerError, LoadedFile, Span, withErrorPrinter } from "./error";
import { CompilerError, ErrorEmitted, LoadedFile, Span } from "./error";
import fs from "fs";
import path from "path";
import { tokenize } from "./lexer";
import { ParseState, parse } from "./parser";
import { resolve } from "./resolve";
import { typeck } from "./typeck";
import { ComplexMap } from "./utils";
export type LoadResult<T> =
| {
ok: true;
value: T;
}
| {
ok: false;
err: CompilerError;
};
export function loadModuleFile(
relativeTo: string,
moduleName: string,
span: Span,
): LoadedFile {
): LoadResult<LoadedFile> {
let searchDir: string;
if (relativeTo.endsWith(".mod.nil")) {
// x/uwu.mod.nil searches in x/
searchDir = path.dirname(relativeTo);
} else if (relativeTo.endsWith(".nil")) {
throw new CompilerError(
`.nil files cannot have submodules. use .mod.nil in a subdirectory`,
span,
);
return {
ok: false,
err: new CompilerError(
`.nil files cannot have submodules. use .mod.nil in a subdirectory`,
span,
),
};
} else {
searchDir = relativeTo;
}
@ -41,13 +55,34 @@ export function loadModuleFile(
});
if (content === undefined || filePath === undefined) {
throw new CompilerError(
`failed to load ${moduleName}, could not find ${options.join(" or ")}`,
span,
);
return {
ok: false,
err: new CompilerError(
`failed to load ${moduleName}, could not find ${options.join(" or ")}`,
span,
),
};
}
return { content, path: filePath };
return { ok: true, value: { content, path: filePath } };
}
function dummyErrorCrate(
id: CrateId,
packageName: string,
emitted: ErrorEmitted,
): DepCrate {
return {
id,
packageName,
rootItems: [],
itemsById: new ComplexMap(),
rootFile: { content: "<dummy>" },
fatalError: emitted,
typeckResults: {
main: undefined,
},
};
}
export const loadCrate: CrateLoader = (
@ -65,27 +100,27 @@ export const loadCrate: CrateLoader = (
return existing;
}
return withErrorPrinter(
(): DepCrate => {
const file = loadModuleFile(".", name, span);
const crateId = gcx.crateId.next();
const crateId = gcx.crateId.next();
const file = loadModuleFile(".", name, span);
if (!file.ok) {
return dummyErrorCrate(crateId, name, gcx.error.emit(file.err));
}
const tokens = tokenize(file);
const parseState: ParseState = { tokens, file };
const ast = parse(name, parseState, crateId);
const resolved = resolve(gcx, ast);
const tokens = tokenize(gcx.error, file.value);
if (!tokens.ok) {
return dummyErrorCrate(crateId, name, tokens.err);
}
const parseState: ParseState = {
tokens: tokens.tokens,
file: file.value,
gcx,
};
const ast = parse(name, parseState, crateId);
const resolved = resolve(gcx, ast);
const typecked = typeck(gcx, resolved);
const typecked = typeck(gcx, resolved);
gcx.finalizedCrates.push(typecked);
return typecked;
},
() => {
throw new CompilerError(
`failed to load crate ${name}: crate contains errors`,
span,
);
},
);
gcx.finalizedCrates.push(typecked);
return typecked;
};