mirror of
https://github.com/Mercantec-GHC/h4-projekt-gruppe-0-sm.git
synced 2025-04-28 08:44:06 +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 UnaryType = "not" | "-";
|
||||||
export type BinaryType =
|
export type BinaryType =
|
||||||
| "+"
|
| "+"
|
||||||
| "*"
|
|
||||||
| "=="
|
|
||||||
| "-"
|
| "-"
|
||||||
|
| "*"
|
||||||
| "/"
|
| "/"
|
||||||
|
| "=="
|
||||||
| "!="
|
| "!="
|
||||||
| "<"
|
| "<"
|
||||||
| ">"
|
| ">"
|
||||||
|
@ -141,58 +141,12 @@ export class Checker {
|
|||||||
return this.checkCallExpr(expr, k, expected);
|
return this.checkCallExpr(expr, k, expected);
|
||||||
case "unary":
|
case "unary":
|
||||||
return todo();
|
return todo();
|
||||||
case "binary": {
|
case "binary":
|
||||||
const res = this.resolveTys(
|
return this.checkBinaryExpr(expr, k, expected);
|
||||||
this.exprTy(k.left),
|
case "block":
|
||||||
this.exprTy(k.right),
|
return this.checkBlock(k.block, expected);
|
||||||
);
|
case "if":
|
||||||
if (!res.ok) {
|
return this.checkIfExpr(expr, k, expected);
|
||||||
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 "loop":
|
case "loop":
|
||||||
return todo();
|
return todo();
|
||||||
case "while":
|
case "while":
|
||||||
@ -261,15 +215,110 @@ export class Checker {
|
|||||||
);
|
);
|
||||||
return Ty({ tag: "error" });
|
return Ty({ tag: "error" });
|
||||||
}
|
}
|
||||||
const _args = kind.args.map((arg, i) =>
|
for (const [i, arg] of kind.args.entries()) {
|
||||||
this.checkExpr(arg, paramTys[i])
|
this.checkExpr(arg, paramTys[i]);
|
||||||
);
|
}
|
||||||
|
|
||||||
const ty = fnTy.kind.returnTy;
|
const ty = fnTy.kind.returnTy;
|
||||||
this.exprTys.set(expr.id, ty);
|
this.exprTys.set(expr.id, ty);
|
||||||
return 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 {
|
private tyTy(ty: ast.Ty): Ty {
|
||||||
return this.tyTys.get(ty.id) ||
|
return this.tyTys.get(ty.id) ||
|
||||||
this.checkTy(ty);
|
this.checkTy(ty);
|
||||||
|
@ -24,7 +24,7 @@ import {
|
|||||||
TyKind,
|
TyKind,
|
||||||
UnaryType,
|
UnaryType,
|
||||||
} from "@slige/ast";
|
} 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 { Lexer } from "./lexer.ts";
|
||||||
import { TokenIter } from "./token.ts";
|
import { TokenIter } from "./token.ts";
|
||||||
import { SigFilter } from "./token.ts";
|
import { SigFilter } from "./token.ts";
|
||||||
@ -726,11 +726,10 @@ export class Parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private parseOr(rs: ExprRestricts): Expr {
|
private parseOr(rs: ExprRestricts): Expr {
|
||||||
const pos = this.span();
|
|
||||||
let left = this.parseAnd(rs);
|
let left = this.parseAnd(rs);
|
||||||
while (true) {
|
while (true) {
|
||||||
if (this.test("or")) {
|
if (this.test("or")) {
|
||||||
left = this.parBinTail(left, pos, rs, this.parseAnd, "or");
|
left = this.parBinTail(left, rs, this.parseAnd, "or");
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -739,11 +738,10 @@ export class Parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private parseAnd(rs: ExprRestricts): Expr {
|
private parseAnd(rs: ExprRestricts): Expr {
|
||||||
const pos = this.span();
|
let left = this.parseEquality(rs);
|
||||||
let left = this.parseEq(rs);
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if (this.test("and")) {
|
if (this.test("and")) {
|
||||||
left = this.parBinTail(left, pos, rs, this.parseEq, "and");
|
left = this.parBinTail(left, rs, this.parseEquality, "and");
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -751,36 +749,33 @@ export class Parser {
|
|||||||
return left;
|
return left;
|
||||||
}
|
}
|
||||||
|
|
||||||
private parseEq(rs: ExprRestricts): Expr {
|
private parseEquality(rs: ExprRestricts): Expr {
|
||||||
const pos = this.span();
|
|
||||||
const left = this.parseComparison(rs);
|
const left = this.parseComparison(rs);
|
||||||
if (this.test("==") || this.test("!=")) {
|
if (this.test("==") || this.test("!=")) {
|
||||||
const op = this.current().type as BinaryType;
|
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;
|
return left;
|
||||||
}
|
}
|
||||||
|
|
||||||
private parseComparison(rs: ExprRestricts): Expr {
|
private parseComparison(rs: ExprRestricts): Expr {
|
||||||
const pos = this.span();
|
|
||||||
const left = this.parseAddSub(rs);
|
const left = this.parseAddSub(rs);
|
||||||
if (
|
if (
|
||||||
this.test("<") || this.test(">") || this.test("<=") ||
|
this.test("<") || this.test(">") || this.test("<=") ||
|
||||||
this.test(">=")
|
this.test(">=")
|
||||||
) {
|
) {
|
||||||
const op = this.current().type as BinaryType;
|
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;
|
return left;
|
||||||
}
|
}
|
||||||
|
|
||||||
private parseAddSub(rs: ExprRestricts): Expr {
|
private parseAddSub(rs: ExprRestricts): Expr {
|
||||||
const pos = this.span();
|
|
||||||
let left = this.parseMulDiv(rs);
|
let left = this.parseMulDiv(rs);
|
||||||
while (true) {
|
while (true) {
|
||||||
if (this.test("+") || this.test("-")) {
|
if (this.test("+") || this.test("-")) {
|
||||||
const op = this.current().type as BinaryType;
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -789,12 +784,11 @@ export class Parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private parseMulDiv(rs: ExprRestricts): Expr {
|
private parseMulDiv(rs: ExprRestricts): Expr {
|
||||||
const pos = this.span();
|
|
||||||
let left = this.parsePrefix(rs);
|
let left = this.parsePrefix(rs);
|
||||||
while (true) {
|
while (true) {
|
||||||
if (this.test("*") || this.test("/")) {
|
if (this.test("*") || this.test("/")) {
|
||||||
const op = this.current().type as BinaryType;
|
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;
|
continue;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -804,7 +798,6 @@ export class Parser {
|
|||||||
|
|
||||||
private parBinTail(
|
private parBinTail(
|
||||||
left: Expr,
|
left: Expr,
|
||||||
span: Span,
|
|
||||||
rs: ExprRestricts,
|
rs: ExprRestricts,
|
||||||
parseRight: (this: Parser, rs: ExprRestricts) => Expr,
|
parseRight: (this: Parser, rs: ExprRestricts) => Expr,
|
||||||
binaryType: BinaryType,
|
binaryType: BinaryType,
|
||||||
@ -813,7 +806,7 @@ export class Parser {
|
|||||||
const right = parseRight.call(this, rs);
|
const right = parseRight.call(this, rs);
|
||||||
return this.expr(
|
return this.expr(
|
||||||
{ tag: "binary", binaryType, left, right },
|
{ tag: "binary", binaryType, left, right },
|
||||||
span,
|
Span.fromto(left.span, right.span),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ fn main() {
|
|||||||
let foo = 5;
|
let foo = 5;
|
||||||
let bar = 7 + foo;
|
let bar = 7 + foo;
|
||||||
|
|
||||||
if foo {} else {}
|
if foo == 5 {} else {}
|
||||||
|
|
||||||
let c = add(foo, bar);
|
let c = add(foo, bar);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user