diff --git a/slige/compiler/ast/ast.ts b/slige/compiler/ast/ast.ts index ea61696..24bc778 100644 --- a/slige/compiler/ast/ast.ts +++ b/slige/compiler/ast/ast.ts @@ -179,10 +179,10 @@ export type RefType = "ref" | "ptr"; export type UnaryType = "not" | "-"; export type BinaryType = | "+" - | "*" - | "==" | "-" + | "*" | "/" + | "==" | "!=" | "<" | ">" diff --git a/slige/compiler/check/checker.ts b/slige/compiler/check/checker.ts index d31b518..bc26418 100644 --- a/slige/compiler/check/checker.ts +++ b/slige/compiler/check/checker.ts @@ -141,58 +141,12 @@ export class Checker { return this.checkCallExpr(expr, k, expected); case "unary": return todo(); - case "binary": { - const res = this.resolveTys( - this.exprTy(k.left), - this.exprTy(k.right), - ); - if (!res.ok) { - this.exprTys.set(expr.id, Ty({ tag: "error" })); - this.report(res.val, expr.span); - return Ty({ tag: "error" }); - } - this.exprTys.set(expr.id, res.val); - return res.val; - } - case "block": { - const ty = this.checkBlock(k.block, expected); - return ty; - } - case "if": { - const cond = this.exprTy(k.cond); - const condRes = this.resolveTys(cond, Ty({ tag: "bool" })); - if (!condRes.ok) { - this.exprTys.set(expr.id, Ty({ tag: "error" })); - this.report("if-condition must be a boolean", k.cond.span); - return Ty({ tag: "error" }); - } - const truthy = this.exprTy(k.truthy); - if (!k.falsy) { - const truthyRes = this.resolveTys( - truthy, - Ty({ tag: "null" }), - ); - if (!truthyRes.ok) { - this.exprTys.set(expr.id, Ty({ tag: "error" })); - this.report( - "if there isn't a falsy-clause, then the truthy clause must evaluate to null", - k.truthy.span, - ); - return Ty({ tag: "error" }); - } - this.exprTys.set(expr.id, Ty({ tag: "null" })); - return Ty({ tag: "null" }); - } - const falsy = this.exprTy(k.falsy); - const bothRes = this.resolveTys(truthy, falsy); - if (!bothRes.ok) { - this.exprTys.set(expr.id, Ty({ tag: "error" })); - this.report(bothRes.val, k.truthy.span); - return Ty({ tag: "error" }); - } - this.exprTys.set(expr.id, bothRes.val); - return bothRes.val; - } + case "binary": + return this.checkBinaryExpr(expr, k, expected); + case "block": + return this.checkBlock(k.block, expected); + case "if": + return this.checkIfExpr(expr, k, expected); case "loop": return todo(); case "while": @@ -261,15 +215,110 @@ export class Checker { ); return Ty({ tag: "error" }); } - const _args = kind.args.map((arg, i) => - this.checkExpr(arg, paramTys[i]) - ); + for (const [i, arg] of kind.args.entries()) { + this.checkExpr(arg, paramTys[i]); + } const ty = fnTy.kind.returnTy; this.exprTys.set(expr.id, ty); return ty; } + private checkBinaryExpr( + expr: ast.Expr, + kind: ast.BinaryExpr, + expected: Ty, + ): Ty { + switch (kind.binaryType) { + case "+": + case "-": + case "*": + case "/": { + const operandRes = this.resolveTys( + this.exprTy(kind.left), + this.exprTy(kind.right), + ); + if (!operandRes.ok) { + this.exprTys.set(expr.id, Ty({ tag: "error" })); + this.report(operandRes.val, expr.span); + return Ty({ tag: "error" }); + } + const operatorRes = this.resolveTys( + operandRes.val, + Ty({ tag: "int" }), + ); + if (!operatorRes.ok) { + this.exprTys.set(expr.id, Ty({ tag: "error" })); + this.report(operatorRes.val, expr.span); + return Ty({ tag: "error" }); + } + this.exprTys.set(expr.id, operatorRes.val); + return operandRes.val; + } + case "==": + case "!=": + case "<": + case ">": + case "<=": + case ">=": + case "or": + case "and": { + const operandRes = this.resolveTys( + this.exprTy(kind.left), + this.exprTy(kind.right), + ); + if (!operandRes.ok) { + this.exprTys.set(expr.id, Ty({ tag: "error" })); + this.report(operandRes.val, expr.span); + return Ty({ tag: "error" }); + } + const ty = Ty({ tag: "bool" }); + this.exprTys.set(expr.id, ty); + return ty; + } + } + } + + private checkIfExpr( + expr: ast.Expr, + kind: ast.IfExpr, + expected: Ty, + ): Ty { + const cond = this.exprTy(kind.cond); + const condRes = this.resolveTys(cond, Ty({ tag: "bool" })); + if (!condRes.ok) { + this.exprTys.set(expr.id, Ty({ tag: "error" })); + this.report("if-condition must be a boolean", kind.cond.span); + return Ty({ tag: "error" }); + } + const truthy = this.exprTy(kind.truthy); + if (!kind.falsy) { + const truthyRes = this.resolveTys( + truthy, + Ty({ tag: "null" }), + ); + if (!truthyRes.ok) { + this.exprTys.set(expr.id, Ty({ tag: "error" })); + this.report( + "if there isn't a falsy-clause, then the truthy clause must evaluate to null", + kind.truthy.span, + ); + return Ty({ tag: "error" }); + } + this.exprTys.set(expr.id, Ty({ tag: "null" })); + return Ty({ tag: "null" }); + } + const falsy = this.exprTy(kind.falsy); + const bothRes = this.resolveTys(truthy, falsy); + if (!bothRes.ok) { + this.exprTys.set(expr.id, Ty({ tag: "error" })); + this.report(bothRes.val, kind.truthy.span); + return Ty({ tag: "error" }); + } + this.exprTys.set(expr.id, bothRes.val); + return bothRes.val; + } + private tyTy(ty: ast.Ty): Ty { return this.tyTys.get(ty.id) || this.checkTy(ty); diff --git a/slige/compiler/parse/parser.ts b/slige/compiler/parse/parser.ts index 5982b50..5569d82 100644 --- a/slige/compiler/parse/parser.ts +++ b/slige/compiler/parse/parser.ts @@ -24,7 +24,7 @@ import { TyKind, UnaryType, } from "@slige/ast"; -import { Ctx, File as CtxFile, Pos, Res, Span, todo } from "@slige/common"; +import { Ctx, File as CtxFile, Res, Span } from "@slige/common"; import { Lexer } from "./lexer.ts"; import { TokenIter } from "./token.ts"; import { SigFilter } from "./token.ts"; @@ -726,11 +726,10 @@ export class Parser { } private parseOr(rs: ExprRestricts): Expr { - const pos = this.span(); let left = this.parseAnd(rs); while (true) { if (this.test("or")) { - left = this.parBinTail(left, pos, rs, this.parseAnd, "or"); + left = this.parBinTail(left, rs, this.parseAnd, "or"); } else { break; } @@ -739,11 +738,10 @@ export class Parser { } private parseAnd(rs: ExprRestricts): Expr { - const pos = this.span(); - let left = this.parseEq(rs); + let left = this.parseEquality(rs); while (true) { if (this.test("and")) { - left = this.parBinTail(left, pos, rs, this.parseEq, "and"); + left = this.parBinTail(left, rs, this.parseEquality, "and"); } else { break; } @@ -751,36 +749,33 @@ export class Parser { return left; } - private parseEq(rs: ExprRestricts): Expr { - const pos = this.span(); + private parseEquality(rs: ExprRestricts): Expr { const left = this.parseComparison(rs); if (this.test("==") || this.test("!=")) { const op = this.current().type as BinaryType; - return this.parBinTail(left, pos, rs, this.parseComparison, op); + return this.parBinTail(left, rs, this.parseComparison, op); } return left; } private parseComparison(rs: ExprRestricts): Expr { - const pos = this.span(); const left = this.parseAddSub(rs); if ( this.test("<") || this.test(">") || this.test("<=") || this.test(">=") ) { const op = this.current().type as BinaryType; - return this.parBinTail(left, pos, rs, this.parseAddSub, op); + return this.parBinTail(left, rs, this.parseAddSub, op); } return left; } private parseAddSub(rs: ExprRestricts): Expr { - const pos = this.span(); let left = this.parseMulDiv(rs); while (true) { if (this.test("+") || this.test("-")) { const op = this.current().type as BinaryType; - left = this.parBinTail(left, pos, rs, this.parseMulDiv, op); + left = this.parBinTail(left, rs, this.parseMulDiv, op); continue; } break; @@ -789,12 +784,11 @@ export class Parser { } private parseMulDiv(rs: ExprRestricts): Expr { - const pos = this.span(); let left = this.parsePrefix(rs); while (true) { if (this.test("*") || this.test("/")) { const op = this.current().type as BinaryType; - left = this.parBinTail(left, pos, rs, this.parsePrefix, op); + left = this.parBinTail(left, rs, this.parsePrefix, op); continue; } break; @@ -804,7 +798,6 @@ export class Parser { private parBinTail( left: Expr, - span: Span, rs: ExprRestricts, parseRight: (this: Parser, rs: ExprRestricts) => Expr, binaryType: BinaryType, @@ -813,7 +806,7 @@ export class Parser { const right = parseRight.call(this, rs); return this.expr( { tag: "binary", binaryType, left, right }, - span, + Span.fromto(left.span, right.span), ); } diff --git a/slige/compiler/program.slg b/slige/compiler/program.slg index fe7847f..863a1a4 100644 --- a/slige/compiler/program.slg +++ b/slige/compiler/program.slg @@ -7,7 +7,7 @@ fn main() { let foo = 5; let bar = 7 + foo; - if foo {} else {} + if foo == 5 {} else {} let c = add(foo, bar); }