mirror of
https://github.com/Mercantec-GHC/h4-projekt-gruppe-0-sm.git
synced 2025-04-27 16:24:07 +02:00
compiler: add assignment stuff
This commit is contained in:
parent
245ed06a3b
commit
8f4ca01f77
@ -32,15 +32,11 @@ export class Checker {
|
||||
}
|
||||
|
||||
private checkBlock(block: ast.Block, expected: Ty): Ty {
|
||||
this.checkStmts(block.stmts);
|
||||
return block.expr &&
|
||||
this.checkExpr(block.expr, expected) ||
|
||||
Ty({ tag: "null" });
|
||||
}
|
||||
|
||||
private checkStmts(stmts: ast.Stmt[]) {
|
||||
}
|
||||
|
||||
private checkLetStmtTy(stmt: ast.Stmt, kind: ast.LetStmt) {
|
||||
if (this.stmtChecked.has(stmt.id)) {
|
||||
return;
|
||||
@ -88,6 +84,78 @@ export class Checker {
|
||||
exhausted(k);
|
||||
}
|
||||
|
||||
public checkAssignStmt(stmt: ast.Stmt, kind: ast.AssignStmt) {
|
||||
if (this.stmtChecked.has(stmt.id)) {
|
||||
return;
|
||||
}
|
||||
this.stmtChecked.add(stmt.id);
|
||||
switch (kind.assignType) {
|
||||
case "=": {
|
||||
const valTy = this.exprTy(kind.value);
|
||||
this.checkAssignableExpr(
|
||||
kind.subject,
|
||||
valTy,
|
||||
kind.subject.span,
|
||||
);
|
||||
return;
|
||||
}
|
||||
case "+=":
|
||||
case "-=": {
|
||||
const re = this.re.exprRes(kind.subject.id);
|
||||
if (re.kind.tag !== "local") {
|
||||
this.report(
|
||||
"cannot assign to expression",
|
||||
kind.subject.span,
|
||||
);
|
||||
this.exprTys.set(kind.subject.id, Ty({ tag: "error" }));
|
||||
return;
|
||||
}
|
||||
const patRe = this.re.patRes(re.kind.id);
|
||||
const patTy = this.patTy(patRe.pat);
|
||||
const tyRes = this.resolveTys(patTy, Ty({ tag: "int" }));
|
||||
if (!tyRes.ok) {
|
||||
this.report(
|
||||
"cannot increment/decrement non-integer",
|
||||
kind.subject.span,
|
||||
);
|
||||
this.exprTys.set(kind.subject.id, Ty({ tag: "error" }));
|
||||
return;
|
||||
}
|
||||
const valTy = this.exprTy(kind.value);
|
||||
const valTyRes = this.resolveTys(valTy, Ty({ tag: "int" }));
|
||||
if (!valTyRes.ok) {
|
||||
if (valTy.kind.tag !== "error") {
|
||||
this.report(
|
||||
"cannot increment/decrement with non-integer",
|
||||
kind.value.span,
|
||||
);
|
||||
}
|
||||
this.exprTys.set(kind.subject.id, Ty({ tag: "error" }));
|
||||
return;
|
||||
}
|
||||
this.exprTys.set(kind.subject.id, valTyRes.val);
|
||||
return;
|
||||
}
|
||||
}
|
||||
exhausted(kind.assignType);
|
||||
}
|
||||
|
||||
private checkAssignableExpr(expr: ast.Expr, ty: Ty, valSpan: Span) {
|
||||
todo();
|
||||
switch (ty.kind.tag) {
|
||||
case "error":
|
||||
this.exprTys.set(expr.id, ty);
|
||||
return;
|
||||
case "unknown":
|
||||
this.exprTys.set(expr.id, ty);
|
||||
return;
|
||||
case "null":
|
||||
case "int":
|
||||
case "bool":
|
||||
case "fn":
|
||||
}
|
||||
}
|
||||
|
||||
public fnItemTy(item: ast.Item, kind: ast.FnItem): Ty {
|
||||
return this.itemTys.get(item.id) ?? this.checkFnItem(item, kind);
|
||||
}
|
||||
|
@ -109,8 +109,9 @@ export class FnLowerer {
|
||||
case "return":
|
||||
case "break":
|
||||
case "continue":
|
||||
case "assign":
|
||||
return todo(k.tag);
|
||||
case "assign":
|
||||
return this.lowerAssignStmt(stmt, k);
|
||||
case "expr": {
|
||||
const rval = this.lowerExpr(k.expr);
|
||||
// ignore the fuck out of the value
|
||||
@ -121,7 +122,7 @@ export class FnLowerer {
|
||||
exhausted(k);
|
||||
}
|
||||
|
||||
private lowerLetStmt(_stmt: ast.Stmt, kind: ast.LetStmt) {
|
||||
private lowerLetStmt(stmt: ast.Stmt, kind: ast.LetStmt) {
|
||||
const val = kind.expr && this.lowerExpr(kind.expr);
|
||||
this.allocatePat(kind.pat);
|
||||
if (val) {
|
||||
@ -136,7 +137,9 @@ export class FnLowerer {
|
||||
return;
|
||||
case "bind": {
|
||||
const ty = this.ch.patTy(pat);
|
||||
const local = this.local(ty, k.ident);
|
||||
const local = k.mut
|
||||
? this.localMut(ty, k.ident)
|
||||
: this.local(ty, k.ident);
|
||||
this.reLocals.set(pat.id, local);
|
||||
return;
|
||||
}
|
||||
@ -166,28 +169,59 @@ export class FnLowerer {
|
||||
exhausted(k);
|
||||
}
|
||||
|
||||
private assignPat(pat: ast.Pat, local: LocalId, proj: ProjElem[] = []) {
|
||||
const k = pat.kind;
|
||||
private lowerAssignStmt(stmt: ast.Stmt, kind: ast.AssignStmt) {
|
||||
this.ch.checkAssignStmt(stmt, kind);
|
||||
const rval = this.lowerExpr(kind.value);
|
||||
switch (kind.assignType) {
|
||||
case "=":
|
||||
return this.assignToExpr(kind.subject, rval, []);
|
||||
case "+=":
|
||||
case "-=":
|
||||
todo();
|
||||
}
|
||||
}
|
||||
|
||||
private assignToExpr(expr: ast.Expr, rval: RVal, proj: ProjElem[]) {
|
||||
const k = expr.kind;
|
||||
switch (k.tag) {
|
||||
case "error":
|
||||
return;
|
||||
case "bind": {
|
||||
const patLocal = this.reLocals.get(pat.id)!;
|
||||
case "path": {
|
||||
const re = this.re.exprRes(expr.id);
|
||||
if (re.kind.tag !== "local") {
|
||||
throw new Error("cannot assign. checker should catch");
|
||||
}
|
||||
const patRe = this.re.patRes(re.kind.id);
|
||||
const local = this.reLocals.get(patRe.pat.id)!;
|
||||
this.addStmt({
|
||||
tag: "assign",
|
||||
place: { local: patLocal, proj: [] },
|
||||
rval: {
|
||||
tag: "use",
|
||||
operand: this.copyOrMoveLocal(
|
||||
local,
|
||||
this.locals.get(local)!.ty,
|
||||
),
|
||||
},
|
||||
place: { local, proj: [] },
|
||||
rval,
|
||||
});
|
||||
return;
|
||||
}
|
||||
case "path":
|
||||
return todo();
|
||||
case "error":
|
||||
case "null":
|
||||
case "int":
|
||||
case "bool":
|
||||
case "str":
|
||||
case "group":
|
||||
case "array":
|
||||
case "repeat":
|
||||
case "struct":
|
||||
case "ref":
|
||||
case "deref":
|
||||
case "elem":
|
||||
case "field":
|
||||
case "index":
|
||||
case "call":
|
||||
case "unary":
|
||||
case "binary":
|
||||
case "block":
|
||||
case "if":
|
||||
case "loop":
|
||||
case "while":
|
||||
case "for":
|
||||
case "c_for":
|
||||
throw new Error("not assignable. checker should catch");
|
||||
}
|
||||
exhausted(k);
|
||||
}
|
||||
@ -454,7 +488,13 @@ export class FnLowerer {
|
||||
|
||||
private local(ty: Ty, ident?: ast.Ident): LocalId {
|
||||
const id = this.localIds.nextThenStep();
|
||||
this.locals.set(id, { id, ty, ident });
|
||||
this.locals.set(id, { id, ty, mut: false, ident });
|
||||
return id;
|
||||
}
|
||||
|
||||
private localMut(ty: Ty, ident?: ast.Ident): LocalId {
|
||||
const id = this.localIds.nextThenStep();
|
||||
this.locals.set(id, { id, ty, mut: true, ident });
|
||||
return id;
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,7 @@ export type LocalId = IdBase & { readonly _: unique symbol };
|
||||
export type Local = {
|
||||
id: LocalId;
|
||||
ty: Ty;
|
||||
mut: boolean;
|
||||
ident?: ast.Ident;
|
||||
};
|
||||
|
||||
|
@ -1004,7 +1004,7 @@ export class Parser {
|
||||
return this.pat({ tag: "error" }, pos);
|
||||
}
|
||||
const ident = this.parseIdent();
|
||||
return this.pat({ tag: "bind", ident, mut: false }, pos);
|
||||
return this.pat({ tag: "bind", ident, mut: true }, pos);
|
||||
}
|
||||
this.report(`expected pattern, got '${this.current().type}'`, pos);
|
||||
this.step();
|
||||
|
@ -1,15 +1,8 @@
|
||||
|
||||
fn add(lhs: int, rhs: int) -> int {
|
||||
lhs + rhs
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let foo = 5;
|
||||
let bar = 7 + foo;
|
||||
let a = 5;
|
||||
|
||||
if foo == 5 {} else {}
|
||||
|
||||
let c = add(foo, bar);
|
||||
a = 10;
|
||||
}
|
||||
|
||||
|
||||
|
@ -61,7 +61,8 @@ export class MirFnStringifyer {
|
||||
|
||||
private localDef(local: Local): string {
|
||||
const ident = local.ident && ` // ${local.ident.text}` || "";
|
||||
return `${this.local(local.id)}: ${this.ty(local.ty)}${ident}`;
|
||||
const mut = local.mut ? "mut " : "";
|
||||
return `${mut}${this.local(local.id)}: ${this.ty(local.ty)}${ident}`;
|
||||
}
|
||||
|
||||
private block(block: Block): string {
|
||||
|
Loading…
x
Reference in New Issue
Block a user