slige/compiler/vtype.ts

82 lines
2.1 KiB
TypeScript

export type VType =
| { type: "error" }
| { type: "unknown" }
| { type: "null" }
| { type: "int" }
| { type: "string" }
| { type: "bool" }
| { type: "array"; inner: VType }
| { type: "struct"; structId: number; fields: VTypeParam[] }
| {
type: "fn";
genericParams?: VTypeGenericParam[];
params: VTypeParam[];
returnType: VType;
fnStmtId: number;
}
| { type: "generic" }
| {
type: "generic_args";
subject: VType;
genericArgs: VType[];
};
export type VTypeParam = {
ident: string;
vtype: VType;
};
export type VTypeGenericParam = {
ident: string;
};
export function vtypesEqual(a: VType, b: VType): boolean {
if (a.type !== b.type) {
return false;
}
if (
["error", "unknown", "null", "int", "string", "bool"]
.includes(a.type)
) {
return true;
}
if (a.type === "array" && b.type === "array") {
return vtypesEqual(a.inner, b.inner);
}
if (a.type === "fn" && b.type === "fn") {
if (a.params.length !== b.params.length) {
return false;
}
for (let i = 0; i < a.params.length; ++i) {
if (!vtypesEqual(a.params[i].vtype, b.params[i].vtype)) {
return false;
}
}
return vtypesEqual(a.returnType, b.returnType);
}
return false;
}
export function vtypeToString(vtype: VType): string {
if (
["error", "unknown", "null", "int", "string", "bool"]
.includes(vtype.type)
) {
return vtype.type;
}
if (vtype.type === "array") {
return `[${vtypeToString(vtype.inner)}]`;
}
if (vtype.type === "fn") {
const paramString = vtype.params.map((param) =>
`${param.ident}: ${vtypeToString(param.vtype)}`
)
.join(", ");
return `fn (${paramString}) -> ${vtypeToString(vtype.returnType)}`;
}
if (vtype.type === "generic") {
return `generic`;
}
throw new Error(`unhandled vtype '${vtype.type}'`);
}