make types
This commit is contained in:
parent
f947c22ffd
commit
d4ced3250b
13
src/ast.ts
13
src/ast.ts
@ -95,11 +95,16 @@ export type NodeWithKind<
|
||||
Tag extends NodeKind["tag"],
|
||||
> = Node & { kind: { tag: Tag } };
|
||||
|
||||
export function assertNodeWithKind<Tag extends NodeKind["tag"]>(
|
||||
node: Node,
|
||||
tag: Tag,
|
||||
): asserts node is NodeWithKind<Tag> {
|
||||
export function assertNodeWithKind<
|
||||
Tag extends NodeKind["tag"],
|
||||
>(node: Node, tag: Tag): asserts node is NodeWithKind<Tag> {
|
||||
if (node.kind.tag !== tag) {
|
||||
throw new Error();
|
||||
}
|
||||
}
|
||||
|
||||
export function isNodeWithKind<
|
||||
Tag extends NodeKind["tag"],
|
||||
>(node: Node, tag: Tag): node is NodeWithKind<Tag> {
|
||||
return node.kind.tag === tag;
|
||||
}
|
||||
|
||||
46
src/front.ts
46
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 {
|
||||
|
||||
20
src/ty.ts
20
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 =
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user