diff --git a/src/front/builtins.ts b/src/front/builtins.ts deleted file mode 100644 index 0fc99c7..0000000 --- a/src/front/builtins.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Ty } from "../ty.ts"; - -export type Builtin = { - id: string; - ty: Ty; -}; - -export const builtins: Builtin[] = [ - { - id: "print_int", - ty: Ty.create("Fn", { - params: [Ty.Int], - retTy: Ty.Void, - }), - }, - { - id: "__add", - ty: Ty.create("Fn", { - params: [Ty.Int, Ty.Int], - retTy: Ty.Int, - }), - }, -]; diff --git a/src/front/check.ts b/src/front/check.ts index ae7e67e..cef3b06 100644 --- a/src/front/check.ts +++ b/src/front/check.ts @@ -1,7 +1,6 @@ import * as ast from "../ast.ts"; import { FileReporter, Loc } from "../diagnostics.ts"; import { Ty } from "../ty.ts"; -import { builtins } from "./builtins.ts"; import { Syms } from "./resolve.ts"; export class Tys { @@ -131,7 +130,8 @@ class Checker { return Ty.Bool; } if (sym.tag === "Builtin") { - return builtins.find((s) => s.id === sym.id)!.ty; + this.error(node.loc, `invalid use of builtin '${sym.id}'`); + this.fail(); } if (sym.tag === "FnParam") { return this.tys.expr(sym.param); @@ -308,6 +308,17 @@ class Checker { } private checkCall(node: ast.NodeWithKind<"CallExpr">): Ty { + if (node.kind.value.is("IdentExpr")) { + const sym = this.syms.get(node.kind.value); + if (sym && sym.tag === "Builtin") { + if (sym.id === "debug_print") { + const _argTys = node.kind.args + .map((arg) => this.tys.expr(arg)); + return Ty.Void; + } + } + } + const calleeTy = this.tys.expr(node.kind.value); const callableTy = calleeTy.is("Fn") diff --git a/src/front/resolve.ts b/src/front/resolve.ts index b746e67..c0d832b 100644 --- a/src/front/resolve.ts +++ b/src/front/resolve.ts @@ -1,6 +1,5 @@ import * as ast from "../ast.ts"; import { FileReporter } from "../diagnostics.ts"; -import { builtins } from "./builtins.ts"; export class Syms { constructor( @@ -113,12 +112,9 @@ export function resolve( class ResolverSyms { static root(): ResolverSyms { return new ResolverSyms( - new Map( - builtins.map<[string, Sym]>((sym) => [ - sym.id, - { tag: "Builtin", id: sym.id }, - ]), - ), + new Map([ + ["debug_print", { tag: "Builtin", id: "debug_print" }], + ]), null, ); } diff --git a/src/middle.ts b/src/middle.ts index 63b3c84..42b22ac 100644 --- a/src/middle.ts +++ b/src/middle.ts @@ -57,109 +57,120 @@ class FnLowerer { return this.lowerLetStmt(stmt); } if (stmt.is("ReturnStmt")) { - const source = stmt.kind.expr - ? this.lowerExpr(stmt.kind.expr) - : this.makeVoid(); - this.pushInst(Ty.Void, "Return", { source }); - this.bbs.push(new BasicBlock()); - return; + return this.lowerReturnStmt(stmt); } if (stmt.is("IfStmt")) { - const cond = this.lowerExpr(stmt.kind.cond); - const condBlock = this.bbs.at(-1)!; - - this.bbs.push(new BasicBlock()); - const truthy = this.bbs.at(-1)!; - this.lowerBlock(stmt.kind.truthy.as("Block")); - const truthyEnd = this.bbs.at(-1)!; - - let falsy: BasicBlock | null = null; - let falsyEnd: BasicBlock | null = null; - - if (stmt.kind.falsy) { - this.bbs.push(new BasicBlock()); - falsy = this.bbs.at(-1)!; - this.lowerBlock(stmt.kind.falsy.as("Block")); - falsyEnd = this.bbs.at(-1)!; - } - - this.bbs.push(new BasicBlock()); - const done = this.bbs.at(-1)!; - - condBlock.insts.push( - new Inst(Ty.Void, { - tag: "Branch", - cond, - truthy, - falsy: falsy ?? done, - }), - ); - truthyEnd.insts.push( - new Inst(Ty.Void, { tag: "Jump", target: falsy ?? done }), - ); - falsyEnd?.insts.push( - new Inst(Ty.Void, { tag: "Jump", target: done }), - ); - return; + return this.lowerIfStmt(stmt); } if (stmt.is("WhileStmt")) { - const before = this.bbs.at(-1)!; - - this.bbs.push(new BasicBlock()); - const body = this.bbs.at(-1)!; - - const after = new BasicBlock(); - this.loopEndMap.set(stmt.id, after); - this.lowerBlock(stmt.kind.body.as("Block")); - - const bodyEnd = this.bbs.at(-1)!; - - this.bbs.push(new BasicBlock()); - const condBlock = this.bbs.at(-1)!; - const cond = this.lowerExpr(stmt.kind.cond); - const condBlockEnd = this.bbs.at(-1)!; - - this.bbs.push(after); - - before.insts.push( - new Inst(Ty.Void, { tag: "Jump", target: condBlock }), - ); - condBlockEnd.insts.push( - new Inst(Ty.Void, { - tag: "Branch", - cond: cond, - truthy: body, - falsy: after, - }), - ); - bodyEnd.insts.push( - new Inst(Ty.Void, { tag: "Jump", target: condBlock }), - ); - return; + return this.lowerWhileStmt(stmt); } if (stmt.is("BreakStmt")) { - const sym = this.syms.get(stmt); - if (sym.tag !== "Loop") { - throw new Error(); - } - const loopEnd = this.loopEndMap.get(sym.stmt.id); - if (!loopEnd) { - throw new Error(); - } - this.pushInst(Ty.Void, "Jump", { target: loopEnd }); - this.bbs.push(new BasicBlock()); - return; + return this.lowerBreakStmt(stmt); } if (stmt.is("AssignStmt")) { return this.lowerAssignStmt(stmt); } if (stmt.is("ExprStmt")) { - this.lowerExpr(stmt.kind.expr); - return; + return this.lowerExpr(stmt.kind.expr); } throw new Error(`'${stmt.kind.tag}' not handled`); } + private lowerReturnStmt(stmt: ast.NodeWithKind<"ReturnStmt">) { + const source = stmt.kind.expr + ? this.lowerExpr(stmt.kind.expr) + : this.makeVoid(); + this.pushInst(Ty.Void, "Return", { source }); + this.bbs.push(new BasicBlock()); + } + + private lowerIfStmt(stmt: ast.NodeWithKind<"IfStmt">) { + const cond = this.lowerExpr(stmt.kind.cond); + const condBlock = this.bbs.at(-1)!; + + this.bbs.push(new BasicBlock()); + const truthy = this.bbs.at(-1)!; + this.lowerBlock(stmt.kind.truthy.as("Block")); + const truthyEnd = this.bbs.at(-1)!; + + let falsy: BasicBlock | null = null; + let falsyEnd: BasicBlock | null = null; + + if (stmt.kind.falsy) { + this.bbs.push(new BasicBlock()); + falsy = this.bbs.at(-1)!; + this.lowerBlock(stmt.kind.falsy.as("Block")); + falsyEnd = this.bbs.at(-1)!; + } + + this.bbs.push(new BasicBlock()); + const done = this.bbs.at(-1)!; + + condBlock.insts.push( + new Inst(Ty.Void, { + tag: "Branch", + cond, + truthy, + falsy: falsy ?? done, + }), + ); + truthyEnd.insts.push( + new Inst(Ty.Void, { tag: "Jump", target: falsy ?? done }), + ); + falsyEnd?.insts.push( + new Inst(Ty.Void, { tag: "Jump", target: done }), + ); + } + + private lowerWhileStmt(stmt: ast.NodeWithKind<"WhileStmt">) { + const before = this.bbs.at(-1)!; + + this.bbs.push(new BasicBlock()); + const body = this.bbs.at(-1)!; + + const after = new BasicBlock(); + this.loopEndMap.set(stmt.id, after); + this.lowerBlock(stmt.kind.body.as("Block")); + + const bodyEnd = this.bbs.at(-1)!; + + this.bbs.push(new BasicBlock()); + const condBlock = this.bbs.at(-1)!; + const cond = this.lowerExpr(stmt.kind.cond); + const condBlockEnd = this.bbs.at(-1)!; + + this.bbs.push(after); + + before.insts.push( + new Inst(Ty.Void, { tag: "Jump", target: condBlock }), + ); + condBlockEnd.insts.push( + new Inst(Ty.Void, { + tag: "Branch", + cond: cond, + truthy: body, + falsy: after, + }), + ); + bodyEnd.insts.push( + new Inst(Ty.Void, { tag: "Jump", target: condBlock }), + ); + } + + private lowerBreakStmt(stmt: ast.NodeWithKind<"BreakStmt">) { + const sym = this.syms.get(stmt); + if (sym.tag !== "Loop") { + throw new Error(); + } + const loopEnd = this.loopEndMap.get(sym.stmt.id); + if (!loopEnd) { + throw new Error(); + } + this.pushInst(Ty.Void, "Jump", { target: loopEnd }); + this.bbs.push(new BasicBlock()); + } + private lowerLetStmt(stmt: ast.NodeWithKind<"LetStmt">) { const ty = this.tys.expr(stmt.kind.param); const expr = this.lowerExpr(stmt.kind.expr); @@ -291,11 +302,7 @@ class FnLowerer { if (expr.kind.value.is("IdentExpr")) { const sym = this.syms.get(expr.kind.value); if (sym.tag === "Builtin") { - if (sym.id === "__add") { - const [left, right] = args; - return this.pushInst(ty, "Add", { left, right }); - } - if (sym.id === "print_int") { + if (sym.id === "debug_print") { return this.pushInst(ty, "DebugPrint", { args }); } throw new Error(`builtin '${sym.id}' not handled`); @@ -306,60 +313,7 @@ class FnLowerer { return this.pushInst(ty, "Call", { callee, args }); } if (expr.is("UnaryExpr")) { - const resultTy = this.tys.expr(expr); - const operandTy = this.tys.expr(expr.kind.expr); - if ( - expr.kind.op === "Negate" && - operandTy.compatibleWith(Ty.Int) && - resultTy.compatibleWith(Ty.Int) - ) { - const operand = this.lowerExpr(expr.kind.expr); - return this.pushInst(Ty.Int, "Negate", { source: operand }); - } - if ( - expr.kind.op === "Not" && - operandTy.compatibleWith(Ty.Bool) && - resultTy.compatibleWith(Ty.Bool) - ) { - const operand = this.lowerExpr(expr.kind.expr); - return this.pushInst(Ty.Bool, "Not", { source: operand }); - } - if (expr.kind.op === "Ref" || expr.kind.op === "RefMut") { - const place = expr.kind.expr; - if (place.is("IdentExpr")) { - const sym = this.syms.get(place); - if (sym.tag === "Let") { - const local = this.localMap.get(sym.param.id); - if (!local) { - throw new Error(); - } - return local; - } - throw new Error( - `${expr.kind.op} with sym ${sym.tag} not handled`, - ); - } - if (place.is("IndexExpr")) { - const placeTy = this.tys.expr(place); - const placeInst = this.lowerPlace(place); - if (placeTy.is("Slice")) { - return placeInst; - } - return this.pushInst(placeTy, "Load", { - source: placeInst, - }); - } - throw new Error( - `${expr.kind.op} with place ${place.kind.tag} not handled`, - ); - } - if (expr.kind.op === "Deref") { - const source = this.lowerExpr(expr.kind.expr); - return this.pushInst(resultTy, "Load", { source }); - } - throw new Error( - `'${expr.kind.op}' with '${resultTy.pretty()}' not handled`, - ); + return this.lowerUnaryExpr(expr); } if (expr.is("BinaryExpr")) { const resultTy = this.tys.expr(expr); @@ -384,6 +338,63 @@ class FnLowerer { throw new Error(`'${expr.kind.tag}' not handled`); } + private lowerUnaryExpr(expr: ast.NodeWithKind<"UnaryExpr">) { + const resultTy = this.tys.expr(expr); + const operandTy = this.tys.expr(expr.kind.expr); + if ( + expr.kind.op === "Negate" && + operandTy.compatibleWith(Ty.Int) && + resultTy.compatibleWith(Ty.Int) + ) { + const operand = this.lowerExpr(expr.kind.expr); + return this.pushInst(Ty.Int, "Negate", { source: operand }); + } + if ( + expr.kind.op === "Not" && + operandTy.compatibleWith(Ty.Bool) && + resultTy.compatibleWith(Ty.Bool) + ) { + const operand = this.lowerExpr(expr.kind.expr); + return this.pushInst(Ty.Bool, "Not", { source: operand }); + } + if (expr.kind.op === "Ref" || expr.kind.op === "RefMut") { + const place = expr.kind.expr; + if (place.is("IdentExpr")) { + const sym = this.syms.get(place); + if (sym.tag === "Let") { + const local = this.localMap.get(sym.param.id); + if (!local) { + throw new Error(); + } + return local; + } + throw new Error( + `${expr.kind.op} with sym ${sym.tag} not handled`, + ); + } + if (place.is("IndexExpr")) { + const placeTy = this.tys.expr(place); + const placeInst = this.lowerPlace(place); + if (placeTy.is("Slice")) { + return placeInst; + } + return this.pushInst(placeTy, "Load", { + source: placeInst, + }); + } + throw new Error( + `${expr.kind.op} with place ${place.kind.tag} not handled`, + ); + } + if (expr.kind.op === "Deref") { + const source = this.lowerExpr(expr.kind.expr); + return this.pushInst(resultTy, "Load", { source }); + } + throw new Error( + `'${expr.kind.op}' with '${resultTy.pretty()}' not handled`, + ); + } + private makeVoid(): Inst { return this.pushInst(Ty.Void, "Void", {}); } diff --git a/tests/array.ethlang b/tests/array.ethlang index 61bbf9d..e31510b 100644 --- a/tests/array.ethlang +++ b/tests/array.ethlang @@ -5,20 +5,20 @@ fn main() let elem: int = array[0]; // expect: 1 - print_int(elem); + debug_print(elem); let ptr_to_array: *[int; 3] = &array; // expect: 2 - print_int(ptr_to_array.*[1]); + debug_print(ptr_to_array.*[1]); let slice: *[int] = &array[..]; // expect: 3 - print_int(slice.*[2]); + debug_print(slice.*[2]); let slice_mut: *mut [int] = &mut array[1..3]; slice_mut.*[0] = 4; // expect: 4 - print_int(array[1]); + debug_print(array[1]); } // vim: syntax=rust commentstring=//\ %s diff --git a/tests/assign.ethlang b/tests/assign.ethlang index 1f61661..a5319b2 100644 --- a/tests/assign.ethlang +++ b/tests/assign.ethlang @@ -4,6 +4,6 @@ fn main() { let v: int = 123; v = 456; - print_int(v); + debug_print(v); } diff --git a/tests/if.ethlang b/tests/if.ethlang index 68c4bf5..e4d968c 100644 --- a/tests/if.ethlang +++ b/tests/if.ethlang @@ -13,7 +13,7 @@ fn main() a = 3; } - print_int(a); + debug_print(a); if false { a = 4; @@ -21,5 +21,5 @@ fn main() a = 5; } - print_int(a); + debug_print(a); } diff --git a/tests/loop.ethlang b/tests/loop.ethlang index 2f696ab..7b4e76e 100644 --- a/tests/loop.ethlang +++ b/tests/loop.ethlang @@ -9,7 +9,7 @@ fn main() a = a + 1; } - print_int(a); + debug_print(a); while a < 10 { if a >= 8 { @@ -18,5 +18,5 @@ fn main() a = a + 1; } - print_int(a); + debug_print(a); } diff --git a/tests/operators.ethlang b/tests/operators.ethlang index 1a7ae06..4a52f93 100644 --- a/tests/operators.ethlang +++ b/tests/operators.ethlang @@ -13,20 +13,20 @@ fn main() let a = 5; let b = 3; - print_int(a + b); - print_int(a - b); - print_int(a * b); - print_int(a * b / 2); - print_int(a % b); - print_int(-a); + debug_print(a + b); + debug_print(a - b); + debug_print(a * b); + debug_print(a * b / 2); + debug_print(a % b); + debug_print(-a); let c = false; if not c { - print_int(123); + debug_print(123); } - print_int(2 * 3 + 4); - print_int(2 * (3 + 4)); + debug_print(2 * 3 + 4); + debug_print(2 * (3 + 4)); } diff --git a/tests/pointer.ethlang b/tests/pointer.ethlang index 7c19ba7..8cca2b1 100644 --- a/tests/pointer.ethlang +++ b/tests/pointer.ethlang @@ -9,21 +9,21 @@ fn main() let a = 1; let b: *int = &a; // expect: 1 - print_int(*b); + debug_print(*b); a = 2; // expect: 2 - print_int(*b); + debug_print(*b); let c: *mut int = &mut a; *c = 3; // expect: 3 - print_int(a); + debug_print(a); // expect: 3 - print_int(*c); + debug_print(*c); change_to(&mut a, 4); // expect: 4 - print_int(a); + debug_print(a); }