mirror of
https://github.com/Mercantec-GHC/h4-projekt-gruppe-0-sm.git
synced 2025-04-28 08:44:06 +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 {
|
private checkBlock(block: ast.Block, expected: Ty): Ty {
|
||||||
this.checkStmts(block.stmts);
|
|
||||||
return block.expr &&
|
return block.expr &&
|
||||||
this.checkExpr(block.expr, expected) ||
|
this.checkExpr(block.expr, expected) ||
|
||||||
Ty({ tag: "null" });
|
Ty({ tag: "null" });
|
||||||
}
|
}
|
||||||
|
|
||||||
private checkStmts(stmts: ast.Stmt[]) {
|
|
||||||
}
|
|
||||||
|
|
||||||
private checkLetStmtTy(stmt: ast.Stmt, kind: ast.LetStmt) {
|
private checkLetStmtTy(stmt: ast.Stmt, kind: ast.LetStmt) {
|
||||||
if (this.stmtChecked.has(stmt.id)) {
|
if (this.stmtChecked.has(stmt.id)) {
|
||||||
return;
|
return;
|
||||||
@ -88,6 +84,78 @@ export class Checker {
|
|||||||
exhausted(k);
|
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 {
|
public fnItemTy(item: ast.Item, kind: ast.FnItem): Ty {
|
||||||
return this.itemTys.get(item.id) ?? this.checkFnItem(item, kind);
|
return this.itemTys.get(item.id) ?? this.checkFnItem(item, kind);
|
||||||
}
|
}
|
||||||
|
@ -109,8 +109,9 @@ export class FnLowerer {
|
|||||||
case "return":
|
case "return":
|
||||||
case "break":
|
case "break":
|
||||||
case "continue":
|
case "continue":
|
||||||
case "assign":
|
|
||||||
return todo(k.tag);
|
return todo(k.tag);
|
||||||
|
case "assign":
|
||||||
|
return this.lowerAssignStmt(stmt, k);
|
||||||
case "expr": {
|
case "expr": {
|
||||||
const rval = this.lowerExpr(k.expr);
|
const rval = this.lowerExpr(k.expr);
|
||||||
// ignore the fuck out of the value
|
// ignore the fuck out of the value
|
||||||
@ -121,7 +122,7 @@ export class FnLowerer {
|
|||||||
exhausted(k);
|
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);
|
const val = kind.expr && this.lowerExpr(kind.expr);
|
||||||
this.allocatePat(kind.pat);
|
this.allocatePat(kind.pat);
|
||||||
if (val) {
|
if (val) {
|
||||||
@ -136,7 +137,9 @@ export class FnLowerer {
|
|||||||
return;
|
return;
|
||||||
case "bind": {
|
case "bind": {
|
||||||
const ty = this.ch.patTy(pat);
|
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);
|
this.reLocals.set(pat.id, local);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -166,28 +169,59 @@ export class FnLowerer {
|
|||||||
exhausted(k);
|
exhausted(k);
|
||||||
}
|
}
|
||||||
|
|
||||||
private assignPat(pat: ast.Pat, local: LocalId, proj: ProjElem[] = []) {
|
private lowerAssignStmt(stmt: ast.Stmt, kind: ast.AssignStmt) {
|
||||||
const k = pat.kind;
|
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) {
|
switch (k.tag) {
|
||||||
case "error":
|
case "path": {
|
||||||
return;
|
const re = this.re.exprRes(expr.id);
|
||||||
case "bind": {
|
if (re.kind.tag !== "local") {
|
||||||
const patLocal = this.reLocals.get(pat.id)!;
|
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({
|
this.addStmt({
|
||||||
tag: "assign",
|
tag: "assign",
|
||||||
place: { local: patLocal, proj: [] },
|
place: { local, proj: [] },
|
||||||
rval: {
|
rval,
|
||||||
tag: "use",
|
|
||||||
operand: this.copyOrMoveLocal(
|
|
||||||
local,
|
|
||||||
this.locals.get(local)!.ty,
|
|
||||||
),
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case "path":
|
case "error":
|
||||||
return todo();
|
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);
|
exhausted(k);
|
||||||
}
|
}
|
||||||
@ -454,7 +488,13 @@ export class FnLowerer {
|
|||||||
|
|
||||||
private local(ty: Ty, ident?: ast.Ident): LocalId {
|
private local(ty: Ty, ident?: ast.Ident): LocalId {
|
||||||
const id = this.localIds.nextThenStep();
|
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;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@ export type LocalId = IdBase & { readonly _: unique symbol };
|
|||||||
export type Local = {
|
export type Local = {
|
||||||
id: LocalId;
|
id: LocalId;
|
||||||
ty: Ty;
|
ty: Ty;
|
||||||
|
mut: boolean;
|
||||||
ident?: ast.Ident;
|
ident?: ast.Ident;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1004,7 +1004,7 @@ export class Parser {
|
|||||||
return this.pat({ tag: "error" }, pos);
|
return this.pat({ tag: "error" }, pos);
|
||||||
}
|
}
|
||||||
const ident = this.parseIdent();
|
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.report(`expected pattern, got '${this.current().type}'`, pos);
|
||||||
this.step();
|
this.step();
|
||||||
|
@ -1,15 +1,8 @@
|
|||||||
|
|
||||||
fn add(lhs: int, rhs: int) -> int {
|
|
||||||
lhs + rhs
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let foo = 5;
|
let a = 5;
|
||||||
let bar = 7 + foo;
|
|
||||||
|
|
||||||
if foo == 5 {} else {}
|
a = 10;
|
||||||
|
|
||||||
let c = add(foo, bar);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -61,7 +61,8 @@ export class MirFnStringifyer {
|
|||||||
|
|
||||||
private localDef(local: Local): string {
|
private localDef(local: Local): string {
|
||||||
const ident = local.ident && ` // ${local.ident.text}` || "";
|
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 {
|
private block(block: Block): string {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user