more eslint rules and fix bugs

This commit is contained in:
nora 2023-07-31 14:50:28 +02:00
parent 12fcc4f1bb
commit 854112da3c
13 changed files with 67 additions and 29 deletions

View file

@ -1,13 +1,22 @@
/* eslint-env node */ /* eslint-env node */
module.exports = { module.exports = {
ignorePatterns: ["/target/**", "/jest.config.js"], ignorePatterns: ["/target/**", "/*.js", "/*.cjs"],
extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended"], extends: [
"eslint:recommended",
"plugin:@typescript-eslint/strict-type-checked",
"plugin:@typescript-eslint/stylistic-type-checked",
],
parser: "@typescript-eslint/parser", parser: "@typescript-eslint/parser",
parserOptions: {
project: true,
tsconfigRootDir: __dirname,
},
plugins: ["@typescript-eslint"], plugins: ["@typescript-eslint"],
root: true, root: true,
rules: { rules: {
// Sometimes you just need a `while(true)`. // Some silly rules forbidding things that are not wrong:
"no-constant-condition": "off", "no-constant-condition": "off",
"no-empty": "off",
// Typescript already checks problematic fallthrough. // Typescript already checks problematic fallthrough.
// The eslint rule is a bit dumb and also complains about // The eslint rule is a bit dumb and also complains about
// obvious clear fallthrough like `case "a": case "b"`. // obvious clear fallthrough like `case "a": case "b"`.
@ -23,5 +32,29 @@ module.exports = {
// `any` is genrally bad, but sometimes it's the nicest solution // `any` is genrally bad, but sometimes it's the nicest solution
// Just let me use it without any ceremony. // Just let me use it without any ceremony.
"@typescript-eslint/no-explicit-any": "off", "@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-unsafe-member-access": "off",
// This needs to be turned off until the AST types are redesigned.
"@typescript-eslint/no-non-null-assertion": "off",
// "value is always truthy" YES IT IS. Typescript already emits errors
// for the important cases here.
"@typescript-eslint/no-unnecessary-condition": "off",
"@typescript-eslint/no-confusing-void-expression": [
"error",
{
ignoreArrowShorthand: true,
},
],
// No, I will use `type` instead of `interface`.
"@typescript-eslint/consistent-type-definitions": ["error", "type"],
// Useful extra lints that are not on by default:
"@typescript-eslint/explicit-module-boundary-types": "warn",
// This has caused several bugs before. Thanks eslint!
"@typescript-eslint/strict-boolean-expressions": [
"error",
{
allowNullableObject: true,
allowNullableBoolean: false,
},
],
}, },
}; };

1
.prettierignore Normal file
View file

@ -0,0 +1 @@
/target

View file

@ -7,7 +7,8 @@
"dev": "node-dev --respawn src/index.ts", "dev": "node-dev --respawn src/index.ts",
"build": "tsc", "build": "tsc",
"fmt": "prettier -w .", "fmt": "prettier -w .",
"test": "jest" "test": "jest",
"lint": "eslint ."
}, },
"author": "", "author": "",
"license": "ISC", "license": "ISC",

View file

@ -460,7 +460,7 @@ export type Folder = {
type: FoldFn<Type>; type: FoldFn<Type>;
}; };
const ITEM_DEFAULT: symbol = Symbol("item must not be overriden"); const ITEM_DEFAULT = Symbol("item must not be overriden");
export const DEFAULT_FOLDER: Folder = { export const DEFAULT_FOLDER: Folder = {
ast() { ast() {

View file

@ -23,7 +23,7 @@ export class CompilerError extends Error {
} }
} }
export function withErrorHandler(input: string, f: () => void) { export function withErrorHandler(input: string, f: () => void): void {
try { try {
f(); f();
} catch (e) { } catch (e) {

View file

@ -44,12 +44,13 @@ function main() {
} }
if (!isValidIdent(packageName)) { if (!isValidIdent(packageName)) {
console.error(`error: package name \`${packageName}\` is not a valid identifer`); console.error(
`error: package name \`${packageName}\` is not a valid identifer`
);
process.exit(1); process.exit(1);
} }
console.log(`package name: '${packageName}'`); console.log(`package name: '${packageName}'`);
withErrorHandler(input, () => { withErrorHandler(input, () => {
const start = Date.now(); const start = Date.now();
@ -92,7 +93,7 @@ function main() {
if (error && error.code === 1) { if (error && error.code === 1) {
console.log(stderr); console.log(stderr);
} else if (error) { } else if (error) {
console.error(`failed to spawn wasm-tools: ${error}`); console.error(`failed to spawn wasm-tools: ${error.message}`);
} else { } else {
if (stderr) { if (stderr) {
console.log(stderr); console.log(stderr);

View file

@ -36,8 +36,7 @@ export type DatalessToken =
| "==" | "=="
| "<=" | "<="
| ">=" | ">="
| "!=" | "!=";
| "!";
export type TokenIdent = { kind: "identifier"; ident: string }; export type TokenIdent = { kind: "identifier"; ident: string };

View file

@ -441,6 +441,7 @@ function lowerExpr(fcx: FuncContext, instrs: wasm.Instr[], expr: Expr) {
kind = `${valty}.ne`; kind = `${valty}.ne`;
break; break;
} }
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const instr: wasm.NumericInstr = { kind } as any; // Typescript is buggy. const instr: wasm.NumericInstr = { kind } as any; // Typescript is buggy.
instrs.push(instr); instrs.push(instr);
} else if (lhsTy.kind === "bool" && rhsTy.kind === "bool") { } else if (lhsTy.kind === "bool" && rhsTy.kind === "bool") {
@ -582,11 +583,11 @@ function lowerExpr(fcx: FuncContext, instrs: wasm.Instr[], expr: Expr) {
switch (expr.lhs.ty!.kind) { switch (expr.lhs.ty!.kind) {
case "tuple": { case "tuple": {
// Tuples have a by-value ABI, so we can simply index. // Tuples have a by-value ABI, so we can simply index.
const lhsSize = argRetAbi(expr.lhs.ty!).length; const lhsSize = argRetAbi(expr.lhs.ty).length;
const resultAbi = argRetAbi(expr.ty!); const resultAbi = argRetAbi(expr.ty!);
const resultSize = resultAbi.length; const resultSize = resultAbi.length;
const wasmIdx = wasmTypeIdxForTupleField( const wasmIdx = wasmTypeIdxForTupleField(
expr.lhs.ty!, expr.lhs.ty,
expr.field.fieldIdx! expr.field.fieldIdx!
); );
@ -625,7 +626,7 @@ function lowerExpr(fcx: FuncContext, instrs: wasm.Instr[], expr: Expr) {
break; break;
} }
case "if": { case "if": {
lowerExpr(fcx, instrs, expr.cond!); lowerExpr(fcx, instrs, expr.cond);
fcx.currentBlockDepth++; fcx.currentBlockDepth++;
const thenInstrs: wasm.Instr[] = []; const thenInstrs: wasm.Instr[] = [];

View file

@ -36,7 +36,7 @@ function printItem(item: Item): string {
return id + printImportDef(item.node); return id + printImportDef(item.node);
} }
case "mod": { case "mod": {
return id +printMod(item.node); return id + printMod(item.node);
} }
} }
} }

View file

@ -444,7 +444,7 @@ export class InferContext {
} }
} }
public assign(lhs_: Ty, rhs_: Ty, span: Span) { public assign(lhs_: Ty, rhs_: Ty, span: Span): void {
const lhs = this.resolveIfPossible(lhs_); const lhs = this.resolveIfPossible(lhs_);
const rhs = this.resolveIfPossible(rhs_); const rhs = this.resolveIfPossible(rhs_);
@ -586,7 +586,7 @@ export function checkBody(
const type: Type | undefined = loweredBindingTy && { const type: Type | undefined = loweredBindingTy && {
...expr.type!, ...expr.type!,
ty: loweredBindingTy!, ty: loweredBindingTy,
}; };
return { return {
@ -689,7 +689,7 @@ export function checkBody(
case "call": { case "call": {
const lhs = this.expr(expr.lhs); const lhs = this.expr(expr.lhs);
lhs.ty = infcx.resolveIfPossible(lhs.ty!); lhs.ty = infcx.resolveIfPossible(lhs.ty!);
const lhsTy = lhs.ty!; const lhsTy = lhs.ty;
if (lhsTy.kind !== "fn") { if (lhsTy.kind !== "fn") {
throw new CompilerError( throw new CompilerError(
`expression of type ${printTy(lhsTy)} is not callable`, `expression of type ${printTy(lhsTy)} is not callable`,
@ -700,7 +700,7 @@ export function checkBody(
const args = expr.args.map((arg) => this.expr(arg)); const args = expr.args.map((arg) => this.expr(arg));
lhsTy.params.forEach((param, i) => { lhsTy.params.forEach((param, i) => {
if (!args[i]) { if (args.length <= i) {
throw new CompilerError( throw new CompilerError(
`missing argument of type ${printTy(param)}`, `missing argument of type ${printTy(param)}`,
expr.span expr.span
@ -905,7 +905,8 @@ export function checkBody(
const resolveTy = (ty: Ty, span: Span) => { const resolveTy = (ty: Ty, span: Span) => {
const resTy = infcx.resolveIfPossible(ty); const resTy = infcx.resolveIfPossible(ty);
if (!resTy) { // TODO: When doing deep resolution, we need to check for _any_ vars.
if (resTy.kind === "var") {
throw new CompilerError("cannot infer type", span); throw new CompilerError("cannot infer type", span);
} }
return resTy; return resTy;

View file

@ -3,7 +3,7 @@ export function encodeUtf8(s: string): Uint8Array {
} }
export class Ids { export class Ids {
nextId: number = 0; nextId = 0;
public next(): number { public next(): number {
return this.nextId++; return this.nextId++;
@ -22,13 +22,13 @@ export function unwrap<T>(value: T | undefined): T {
* It uses JSON+string equality instead of refernece equality. * It uses JSON+string equality instead of refernece equality.
*/ */
export class ComplexMap<K, V> { export class ComplexMap<K, V> {
inner: Map<string | number, V> = new Map(); inner = new Map<string | number, V>();
public get(key: K): V | undefined { public get(key: K): V | undefined {
return this.inner.get(this.mangleKey(key)); return this.inner.get(this.mangleKey(key));
} }
public set(key: K, value: V) { public set(key: K, value: V): void {
this.inner.set(this.mangleKey(key), value); this.inner.set(this.mangleKey(key), value);
} }

View file

@ -265,6 +265,7 @@ export type ControlInstr =
export type Instr = export type Instr =
| NumericInstr | NumericInstr
// eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents
| VectorInstr | VectorInstr
| ReferenceInstr | ReferenceInstr
| ParametricInstr | ParametricInstr

View file

@ -140,8 +140,8 @@ function printString(s: string, f: FmtCtx) {
function printBinaryString(buf: Uint8Array, f: FmtCtx) { function printBinaryString(buf: Uint8Array, f: FmtCtx) {
const parts: string[] = []; const parts: string[] = [];
for (let i = 0; i < buf.length; i++) {
const byte = buf[i]; buf.forEach((byte) => {
const noEscape = const noEscape =
(byte > 0x30 && byte <= 0x5a) || (byte > 0x61 && byte <= 0x71); (byte > 0x30 && byte <= 0x5a) || (byte > 0x61 && byte <= 0x71);
if (noEscape) { if (noEscape) {
@ -149,13 +149,13 @@ function printBinaryString(buf: Uint8Array, f: FmtCtx) {
} else { } else {
parts.push(`\\${byte.toString(16).padStart(2, "0")}`); parts.push(`\\${byte.toString(16).padStart(2, "0")}`);
} }
} });
f.word(`"${parts.join("")}"`); f.word(`"${parts.join("")}"`);
} }
function printId(id: string | undefined, f: FmtCtx) { function printId(id: string | undefined, f: FmtCtx) {
if (id) { if (id !== undefined) {
f.word(`$${id}`); f.word(`$${id}`);
} }
} }
@ -215,7 +215,7 @@ function printBlockType(type: Blocktype, f: FmtCtx) {
} }
function printMemarg(arg: MemArg, f: FmtCtx) { function printMemarg(arg: MemArg, f: FmtCtx) {
if (arg.offset /*0->false*/) { if (arg.offset === undefined || arg.offset === 0) {
f.word(`offset=${arg.offset}`); f.word(`offset=${arg.offset}`);
} }
if (arg.align !== undefined) { if (arg.align !== undefined) {
@ -437,7 +437,7 @@ function printInstr(instr: Instr, f: FmtCtx) {
f.controlFlow(instr.kind); f.controlFlow(instr.kind);
f.word(instr.func); f.word(instr.func);
const name = f.mod.funcs[instr.func]?._name; const name = f.mod.funcs[instr.func]?._name;
if (name) { if (name !== undefined) {
f.comment(name); f.comment(name);
} }
break; break;