diff --git a/src/ast.ts b/src/ast.ts index 5a2e946..daa0a79 100644 --- a/src/ast.ts +++ b/src/ast.ts @@ -95,11 +95,16 @@ export type NodeWithKind< Tag extends NodeKind["tag"], > = Node & { kind: { tag: Tag } }; -export function assertNodeWithKind( - node: Node, - tag: Tag, -): asserts node is NodeWithKind { +export function assertNodeWithKind< + Tag extends NodeKind["tag"], +>(node: Node, tag: Tag): asserts node is NodeWithKind { if (node.kind.tag !== tag) { throw new Error(); } } + +export function isNodeWithKind< + Tag extends NodeKind["tag"], +>(node: Node, tag: Tag): node is NodeWithKind { + return node.kind.tag === tag; +} diff --git a/src/front.ts b/src/front.ts index be275c3..eb68cea 100644 --- a/src/front.ts +++ b/src/front.ts @@ -24,10 +24,52 @@ export class Checker { private checkNode(node: ast.Node): Ty { 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 { diff --git a/src/ty.ts b/src/ty.ts index f2b474f..37bec0b 100644 --- a/src/ty.ts +++ b/src/ty.ts @@ -33,6 +33,26 @@ export class Ty { public id: number, 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 =