make types

This commit is contained in:
sfja 2026-03-09 19:00:41 +01:00
parent f947c22ffd
commit d4ced3250b
3 changed files with 73 additions and 6 deletions

View File

@ -95,11 +95,16 @@ export type NodeWithKind<
Tag extends NodeKind["tag"], Tag extends NodeKind["tag"],
> = Node & { kind: { tag: Tag } }; > = Node & { kind: { tag: Tag } };
export function assertNodeWithKind<Tag extends NodeKind["tag"]>( export function assertNodeWithKind<
node: Node, Tag extends NodeKind["tag"],
tag: Tag, >(node: Node, tag: Tag): asserts node is NodeWithKind<Tag> {
): asserts node is NodeWithKind<Tag> {
if (node.kind.tag !== tag) { if (node.kind.tag !== tag) {
throw new Error(); throw new Error();
} }
} }
export function isNodeWithKind<
Tag extends NodeKind["tag"],
>(node: Node, tag: Tag): node is NodeWithKind<Tag> {
return node.kind.tag === tag;
}

View File

@ -24,10 +24,52 @@ export class Checker {
private checkNode(node: ast.Node): Ty { private checkNode(node: ast.Node): Ty {
const k = node.kind; const k = node.kind;
if (k.tag === "FnStmt") { if (ast.isNodeWithKind(node, "FnStmt")) {
return this.checkFnStmt(node);
} }
throw new Error("not checked"); if (ast.isNodeWithKind(node, "IdentTy")) {
switch (node.kind.ident) {
case "int":
return Ty.Int;
default:
this.error(node.line, `unknown type '${node.kind.ident}'`);
}
}
throw new Error(`'${k.tag}' not checked`);
}
private checkFnStmt(stmt: ast.NodeWithKind<"FnStmt">): Ty {
const k = stmt.kind;
const params = k.params.map((param) => this.check(param));
const retTy = k.retTy ? this.check(k.retTy) : Ty.Void;
k.body.visit({
visit: (node) => {
if (ast.isNodeWithKind(node, "ReturnStmt")) {
if (node.kind.expr) {
const ty = this.check(node.kind.expr);
} else {
}
}
},
});
const ty = Ty.create("Fn", { params, retTy });
return Ty.create("FnStmt", { stmt, ty });
}
private typesCompatible(a: Ty, b: Ty): boolean {
const ak = a.kind;
const bk = b.kind;
if (ak.tag === "Error") {
return false;
}
if (ak.tag === "Void") {
return bk.tag === "Void";
}
} }
private error(line: number, message: string): never { private error(line: number, message: string): never {

View File

@ -33,6 +33,26 @@ export class Ty {
public id: number, public id: number,
public kind: TyKind, public kind: TyKind,
) {} ) {}
isKind<
Tag extends TyKind["tag"],
>(tag: Tag): this is Ty & { kind: { tag: Tag } } {
return this.kind.tag === tag;
}
compatibleWith(other: Ty): boolean {
if (this.isKind("Error")) {
return false;
}
if (this.isKind("Void")) {
return other.isKind("Void");
}
if (this.isKind("Int")) {
return other.isKind("Int");
}
if (this.isKind("Fn")) {
}
}
} }
export type TyKind = export type TyKind =