export type VType = | { type: "" } | { type: "error" } | { type: "unknown" } | { type: "null" } | { type: "int" } | { type: "string" } | { type: "bool" } | { type: "array"; inner: VType } | { type: "struct"; fields: VTypeParam[] } | { type: "fn"; params: VTypeParam[]; returnType: VType }; export type VTypeParam = { ident: string; vtype: VType; }; export function vtypesEqual(a: VType, b: VType): boolean { if (a.type !== b.type) { return false; } if ( ["error", "unknown", "null", "int", "string", "bool", "struct"] .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", "struct"] .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)}`; } throw new Error(`unhandled vtype '${vtype.type}'`); }