mirror of
https://github.com/Mercantec-GHC/h4-projekt-gruppe-0-sm.git
synced 2025-04-27 16:24:07 +02:00
compiler: equality
This commit is contained in:
parent
aa35b6f35d
commit
245ed06a3b
@ -179,10 +179,10 @@ export type RefType = "ref" | "ptr";
|
||||
export type UnaryType = "not" | "-";
|
||||
export type BinaryType =
|
||||
| "+"
|
||||
| "*"
|
||||
| "=="
|
||||
| "-"
|
||||
| "*"
|
||||
| "/"
|
||||
| "=="
|
||||
| "!="
|
||||
| "<"
|
||||
| ">"
|
||||
|
@ -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);
|
||||
|
@ -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),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user