This commit is contained in:
nora 2023-07-30 16:54:04 +02:00
parent 50e82066c9
commit 6d2a2fe474
9 changed files with 443 additions and 98 deletions

View file

@ -1,6 +1,7 @@
import {
Ast,
binaryExprPrecedenceClass,
BuiltinName,
COMPARISON_KINDS,
DEFAULT_FOLDER,
EQUALITY_KINDS,
@ -21,12 +22,17 @@ import {
TY_STRING,
TY_UNIT,
TyFn,
tyIsUnit,
Type,
TyStruct,
} from "./ast";
import { CompilerError, Span } from "./error";
import { printTy } from "./printer";
function mkTyFn(params: Ty[], returnTy: Ty): Ty {
return { kind: "fn", params, returnTy };
}
function builtinAsTy(name: string, span: Span): Ty {
switch (name) {
case "String": {
@ -47,13 +53,25 @@ function builtinAsTy(name: string, span: Span): Ty {
}
}
function typeOfBuiltinValue(name: string, span: Span): Ty {
function typeOfBuiltinValue(name: BuiltinName, span: Span): Ty {
switch (name) {
case "false":
case "true":
return TY_BOOL;
case "print":
return { kind: "fn", params: [TY_STRING], returnTy: TY_UNIT };
return mkTyFn([TY_STRING], TY_UNIT);
case "__i32_store":
return mkTyFn([TY_I32, TY_I32], TY_UNIT);
case "__i64_store":
return mkTyFn([TY_I32, TY_INT], TY_UNIT);
case "__i32_load":
return mkTyFn([TY_I32], TY_I32);
case "__i64_load":
return mkTyFn([TY_I32], TY_INT);
case "__string_ptr":
return mkTyFn([TY_STRING], TY_I32);
case "__string_len":
return mkTyFn([TY_STRING], TY_I32);
default: {
throw new CompilerError(`\`${name}\` cannot be used as a value`, span);
}
@ -103,7 +121,8 @@ export function typeck(ast: Ast): Ast {
}
itemTys.set(index, null);
switch (item.kind) {
case "function": {
case "function":
case "import": {
const args = item.node.params.map((arg) => lowerAstTy(arg.type));
const returnTy: Ty = item.node.returnType
? lowerAstTy(item.node.returnType)
@ -182,6 +201,58 @@ export function typeck(ast: Ast): Ast {
},
};
}
case "import": {
const fnTy = typeOfItem(item.id) as TyFn;
fnTy.params.forEach((param, i) => {
switch (param.kind) {
case "int":
case "i32":
break;
default: {
throw new CompilerError(
`import parameters must be I32 or Int`,
item.node.params[i].span
);
}
}
});
if (!tyIsUnit(fnTy.returnTy)) {
switch (fnTy.returnTy.kind) {
case "int":
case "i32":
break;
default: {
throw new CompilerError(
`import return must be I32 or Int`,
item.node.returnType!.span
);
}
}
}
const returnType = item.node.returnType && {
...item.node.returnType,
ty: fnTy.returnTy,
};
return {
...item,
kind: "import",
node: {
module: item.node.module,
func: item.node.func,
name: item.node.name,
params: item.node.params.map((arg, i) => ({
...arg,
type: { ...arg.type, ty: fnTy.params[i] },
})),
returnType,
ty: fnTy,
},
};
}
case "type": {
const fieldNames = new Set();
item.node.fields.forEach(({ name }) => {
@ -436,7 +507,17 @@ export function checkBody(
type,
(ident) => {
const res = ident.res!;
return typeOf(res, ident.span);
switch (res.kind) {
case "local": {
const idx = localTys.length - 1 - res.index;
return localTys[idx];
}
case "item": {
return typeOfItem(res.index);
}
case "builtin":
return builtinAsTy(res.name, ident.span);
}
},
typeOfItem
);
@ -502,7 +583,14 @@ export function checkBody(
break;
}
case "int": {
ty = TY_INT;
switch (expr.value.type) {
case "Int":
ty = TY_INT;
break;
case "I32":
ty = TY_I32;
break;
}
break;
}
}
@ -721,6 +809,9 @@ function checkBinary(expr: Expr & ExprBinary): Expr {
if (lhsTy.kind === "int" && rhsTy.kind === "int") {
return { ...expr, ty: TY_INT };
}
if (lhsTy.kind === "i32" && rhsTy.kind === "i32") {
return { ...expr, ty: TY_I32 };
}
if (LOGICAL_KINDS.includes(expr.binaryKind)) {
if (lhsTy.kind === "bool" && rhsTy.kind === "bool") {