mirror of
https://git.sfja.dk/Mikkel/slige.git
synced 2025-01-18 19:36:32 +00:00
add type checking
This commit is contained in:
parent
d4ea73de1d
commit
8deda48ca6
@ -91,66 +91,12 @@ export class Checker {
|
|||||||
return this.checkBinaryExpr(expr);
|
return this.checkBinaryExpr(expr);
|
||||||
case "group":
|
case "group":
|
||||||
return this.checkExpr(expr.kind.expr);
|
return this.checkExpr(expr.kind.expr);
|
||||||
case "field": {
|
case "field":
|
||||||
const subject = this.checkExpr(expr.kind.subject);
|
return this.checkFieldExpr(expr);
|
||||||
if (subject.type !== "struct") {
|
case "index":
|
||||||
this.report("cannot use field on non-struct", pos);
|
return this.checkIndexExpr(expr);
|
||||||
return { type: "error" };
|
case "call":
|
||||||
}
|
return this.checkCallExpr(expr);
|
||||||
const value = expr.kind.value;
|
|
||||||
const found = subject.fields.find((param) =>
|
|
||||||
param.ident === value
|
|
||||||
);
|
|
||||||
if (!found) {
|
|
||||||
this.report(
|
|
||||||
`no field named '${expr.kind.value}' on struct`,
|
|
||||||
pos,
|
|
||||||
);
|
|
||||||
return { type: "error" };
|
|
||||||
}
|
|
||||||
return found.vtype;
|
|
||||||
}
|
|
||||||
case "index": {
|
|
||||||
const subject = this.checkExpr(expr.kind.subject);
|
|
||||||
if (subject.type !== "array") {
|
|
||||||
this.report("cannot index on non-array", pos);
|
|
||||||
return { type: "error" };
|
|
||||||
}
|
|
||||||
return subject.inner;
|
|
||||||
}
|
|
||||||
case "call": {
|
|
||||||
const subject = this.checkExpr(expr.kind.subject);
|
|
||||||
if (subject.type !== "fn") {
|
|
||||||
this.report("cannot call non-fn", pos);
|
|
||||||
return { type: "error" };
|
|
||||||
}
|
|
||||||
const args = expr.kind.args.map((arg) =>
|
|
||||||
this.checkExpr(arg)
|
|
||||||
);
|
|
||||||
if (args.length !== subject.params.length) {
|
|
||||||
this.report(
|
|
||||||
`incorrect number of arguments` +
|
|
||||||
`, expected ${subject.params.length}`,
|
|
||||||
pos,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
for (let i = 0; i < args.length; ++i) {
|
|
||||||
if (!vtypesEqual(args[i], subject.params[i].vtype)) {
|
|
||||||
this.report(
|
|
||||||
`incorrect argument ${i} '${
|
|
||||||
subject.params[i].ident
|
|
||||||
}'` +
|
|
||||||
`, expected ${
|
|
||||||
vtypeToString(subject.params[i].vtype)
|
|
||||||
}` +
|
|
||||||
`, got ${vtypeToString(args[i])}`,
|
|
||||||
pos,
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return subject.returnType;
|
|
||||||
}
|
|
||||||
case "unary":
|
case "unary":
|
||||||
case "if":
|
case "if":
|
||||||
case "loop":
|
case "loop":
|
||||||
@ -170,10 +116,10 @@ export class Checker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public checkBinaryExpr(expr: Expr): VType {
|
public checkBinaryExpr(expr: Expr): VType {
|
||||||
const pos = expr.pos;
|
|
||||||
if (expr.kind.type !== "binary") {
|
if (expr.kind.type !== "binary") {
|
||||||
throw new Error();
|
throw new Error();
|
||||||
}
|
}
|
||||||
|
const pos = expr.pos;
|
||||||
const left = this.checkExpr(expr.kind.left);
|
const left = this.checkExpr(expr.kind.left);
|
||||||
const right = this.checkExpr(expr.kind.right);
|
const right = this.checkExpr(expr.kind.right);
|
||||||
for (const operation of simpleBinaryOperations) {
|
for (const operation of simpleBinaryOperations) {
|
||||||
@ -197,6 +143,73 @@ export class Checker {
|
|||||||
);
|
);
|
||||||
return { type: "error" };
|
return { type: "error" };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public checkFieldExpr(expr: Expr): VType {
|
||||||
|
if (expr.kind.type !== "field") {
|
||||||
|
throw new Error();
|
||||||
|
}
|
||||||
|
const pos = expr.pos;
|
||||||
|
const subject = this.checkExpr(expr.kind.subject);
|
||||||
|
if (subject.type !== "struct") {
|
||||||
|
this.report("cannot use field on non-struct", pos);
|
||||||
|
return { type: "error" };
|
||||||
|
}
|
||||||
|
const value = expr.kind.value;
|
||||||
|
const found = subject.fields.find((param) => param.ident === value);
|
||||||
|
if (!found) {
|
||||||
|
this.report(
|
||||||
|
`no field named '${expr.kind.value}' on struct`,
|
||||||
|
pos,
|
||||||
|
);
|
||||||
|
return { type: "error" };
|
||||||
|
}
|
||||||
|
return found.vtype;
|
||||||
|
}
|
||||||
|
|
||||||
|
public checkIndexExpr(expr: Expr): VType {
|
||||||
|
if (expr.kind.type !== "index") {
|
||||||
|
throw new Error();
|
||||||
|
}
|
||||||
|
const pos = expr.pos;
|
||||||
|
const subject = this.checkExpr(expr.kind.subject);
|
||||||
|
if (subject.type !== "array") {
|
||||||
|
this.report("cannot index on non-array", pos);
|
||||||
|
return { type: "error" };
|
||||||
|
}
|
||||||
|
return subject.inner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public checkCallExpr(expr: Expr): VType {
|
||||||
|
if (expr.kind.type !== "call") {
|
||||||
|
throw new Error();
|
||||||
|
}
|
||||||
|
const pos = expr.pos;
|
||||||
|
const subject = this.checkExpr(expr.kind.subject);
|
||||||
|
if (subject.type !== "fn") {
|
||||||
|
this.report("cannot call non-fn", pos);
|
||||||
|
return { type: "error" };
|
||||||
|
}
|
||||||
|
const args = expr.kind.args.map((arg) => this.checkExpr(arg));
|
||||||
|
if (args.length !== subject.params.length) {
|
||||||
|
this.report(
|
||||||
|
`incorrect number of arguments` +
|
||||||
|
`, expected ${subject.params.length}`,
|
||||||
|
pos,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
for (let i = 0; i < args.length; ++i) {
|
||||||
|
if (!vtypesEqual(args[i], subject.params[i].vtype)) {
|
||||||
|
this.report(
|
||||||
|
`incorrect argument ${i} '${subject.params[i].ident}'` +
|
||||||
|
`, expected ${vtypeToString(subject.params[i].vtype)}` +
|
||||||
|
`, got ${vtypeToString(args[i])}`,
|
||||||
|
pos,
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return subject.returnType;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const simpleBinaryOperations: {
|
const simpleBinaryOperations: {
|
||||||
|
@ -20,7 +20,7 @@ export function vtypesEqual(a: VType, b: VType): boolean {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
["error", "unknown", "null", "int", "string", "bool", "struct"]
|
["error", "unknown", "null", "int", "string", "bool"]
|
||||||
.includes(a.type)
|
.includes(a.type)
|
||||||
) {
|
) {
|
||||||
return true;
|
return true;
|
||||||
@ -44,7 +44,7 @@ export function vtypesEqual(a: VType, b: VType): boolean {
|
|||||||
|
|
||||||
export function vtypeToString(vtype: VType): string {
|
export function vtypeToString(vtype: VType): string {
|
||||||
if (
|
if (
|
||||||
["error", "unknown", "null", "int", "string", "bool", "struct"]
|
["error", "unknown", "null", "int", "string", "bool"]
|
||||||
.includes(vtype.type)
|
.includes(vtype.type)
|
||||||
) {
|
) {
|
||||||
return vtype.type;
|
return vtype.type;
|
||||||
|
Loading…
Reference in New Issue
Block a user