allocators and type aliases

This commit is contained in:
nora 2023-08-03 13:22:35 +02:00
parent 60c743d656
commit f05e5520f3
16 changed files with 283 additions and 121 deletions

View file

@ -144,10 +144,20 @@ export type FunctionArg<P extends Phase> = {
export type TypeDef<P extends Phase> = {
name: string;
fields: FieldDef<P>[];
type: TypeDefKind<P>;
ty?: TyStruct;
};
export type TypeDefKind<P extends Phase> =
| {
kind: "struct";
fields: FieldDef<P>[];
}
| {
kind: "alias";
type: Type<P>;
};
export type FieldDef<P extends Phase> = {
name: Ident;
type: Type<P>;
@ -624,15 +634,29 @@ export function superFoldItem<From extends Phase, To extends Phase>(
};
}
case "type": {
const fields = item.node.fields.map(({ name, type }) => ({
name,
type: folder.type(type),
}));
const typeKind = item.node.type;
let type: TypeDefKind<To>;
switch (typeKind.kind) {
case "struct": {
const fields = typeKind.fields.map(({ name, type }) => ({
name,
type: folder.type(type),
}));
type = { kind: "struct", fields };
break;
}
case "alias": {
type = {
kind: "alias",
type: folder.type(typeKind.type),
};
}
}
return {
...item,
kind: "type",
node: { name: item.node.name, fields },
node: { name: item.node.name, type },
};
}
case "import": {

View file

@ -36,8 +36,8 @@ const WASM_PAGE = 65536;
const DUMMY_IDX = 9999999;
const ALLOCATE_ITEM: string[] = ["std", "rt", "allocateItem"];
const DEALLOCATE_ITEM: string[] = ["std", "rt", "deallocateItem"];
const ALLOCATE_ITEM: string[] = ["std", "rt", "alloc", "allocateItem"];
const DEALLOCATE_ITEM: string[] = ["std", "rt", "alloc", "deallocateItem"];
type RelocationKind =
| {

View file

@ -79,7 +79,11 @@ export function parseArgs(hardcodedInput: string): Options {
}
input = fs.readFileSync(filename, { encoding: "utf-8" });
packageName = path.basename(filename, ".nil");
if (filename.endsWith(".mod.nil")) {
packageName = path.basename(filename, ".mod.nil");
} else {
packageName = path.basename(filename, ".nil");
}
const debugArg = process.argv.find((arg) => arg.startsWith("--debug="));
if (debugArg !== undefined) {

View file

@ -13,9 +13,14 @@ import { GlobalContext, parseArgs } from "./context";
import { loadCrate } from "./loader";
const INPUT = `
type A = { a: Int };
type A = struct { a: Int };
type What = What;
type Uwu = (Int, Int);
function main() = (
let a: What = 0;
uwu();
);
@ -28,7 +33,7 @@ function uwu() = (
/*-1*/
);
type B = {
type B = struct {
a: (Int, Int, Int, Int, Int),
};
@ -59,7 +64,9 @@ function main() {
() => {
const start = Date.now();
gcx.crateLoader(gcx, "std", Span.startOfFile(file));
if (packageName !== "std") {
gcx.crateLoader(gcx, "std", Span.startOfFile(file));
}
const tokens = tokenize(file);
if (debug.has("tokens")) {

View file

@ -13,6 +13,7 @@ export type DatalessToken =
| "extern"
| "mod"
| "global"
| "struct"
| "("
| ")"
| "{"
@ -323,6 +324,7 @@ const KEYOWRDS: DatalessToken[] = [
"extern",
"mod",
"global",
"struct",
];
const KEYWORD_SET = new Set<string>(KEYOWRDS);

View file

@ -31,6 +31,7 @@ import {
ItemId,
GlobalItem,
StructLiteralField,
TypeDefKind,
} from "./ast";
import { CompilerError, LoadedFile, Span } from "./error";
import {
@ -107,32 +108,46 @@ function parseItem(t: State): [State, Item<Parsed>] {
let name;
[t, name] = expectNext<TokenIdent>(t, "identifier");
[t] = expectNext(t, "=");
[t] = expectNext(t, "{");
let fields;
[t, fields] = parseCommaSeparatedList<FieldDef<Parsed>>(t, "}", (t) => {
let name;
[t, name] = expectNext<TokenIdent>(t, "identifier");
[t] = expectNext(t, ":");
let type;
[t, type] = parseType(t);
return [
t,
{
name: {
name: name.ident,
span: name.span,
let type: TypeDefKind<Parsed>;
let struct;
[t, struct] = eat(t, "struct");
if (struct) {
[t] = expectNext(t, "{");
let fields;
[t, fields] = parseCommaSeparatedList<FieldDef<Parsed>>(t, "}", (t) => {
let name;
[t, name] = expectNext<TokenIdent>(t, "identifier");
[t] = expectNext(t, ":");
let type;
[t, type] = parseType(t);
return [
t,
{
name: {
name: name.ident,
span: name.span,
},
type,
},
type,
},
];
});
];
});
type = { kind: "struct", fields };
} else {
let aliased: Type<Parsed>;
[t, aliased] = parseType(t);
type = { kind: "alias", type: aliased };
}
[t] = expectNext(t, ";");
const def: TypeDef<Parsed> = {
name: name.ident,
fields,
type,
};
return [

View file

@ -63,14 +63,22 @@ function printFunction(func: FunctionDef<AnyPhase>): string {
}
function printTypeDef(type: TypeDef<AnyPhase>): string {
const fields = type.fields.map(
({ name, type }) => `${ind(1)}${name.name}: ${printType(type)},`,
);
switch (type.type.kind) {
case "struct": {
const { fields } = type.type;
const fieldPart =
type.fields.length === 0 ? "{}" : `{\n${fields.join("\n")}\n}`;
const fieldStr = fields.map(
({ name, type }) => `${ind(1)}${name.name}: ${printType(type)},`,
);
const fieldPart =
fields.length === 0 ? "{}" : `{\n${fieldStr.join("\n")}\n}`;
return `type ${type.name} = ${fieldPart};`;
return `type ${type.name} = ${fieldPart};`;
}
case "alias": {
return `type ${type.name} = ${printType(type.type.type)}`;
}
}
}
function printImportDef(def: ImportDef<AnyPhase>): string {

View file

@ -175,23 +175,29 @@ export function typeck(
return ty;
}
case "type": {
const ty: Ty = {
kind: "struct",
name: item.node.name,
fields: [
/*dummy*/
],
};
switch (item.node.type.kind) {
case "struct": {
const ty: Ty = {
kind: "struct",
name: item.node.name,
fields: [
/*dummy*/
],
};
itemTys.set(item.id, ty);
itemTys.set(item.id, ty);
const fields = item.node.fields.map<[string, Ty]>(({ name, type }) => [
name.name,
lowerAstTy(type),
]);
const fields = item.node.type.fields.map<[string, Ty]>(
({ name, type }) => [name.name, lowerAstTy(type)],
);
ty.fields = fields;
return ty;
ty.fields = fields;
return ty;
}
case "alias": {
return lowerAstTy(item.node.type.type);
}
}
}
case "mod": {
throw new CompilerError(
@ -313,32 +319,51 @@ export function typeck(
};
}
case "type": {
const fieldNames = new Set();
item.node.fields.forEach(({ name }) => {
if (fieldNames.has(name)) {
throw new CompilerError(
`type ${item.node.name} has a duplicate field: ${name.name}`,
name.span,
);
}
fieldNames.add(name);
});
switch (item.node.type.kind) {
case "struct": {
const fieldNames = new Set();
item.node.type.fields.forEach(({ name }) => {
if (fieldNames.has(name)) {
throw new CompilerError(
`type ${item.node.name} has a duplicate field: ${name.name}`,
name.span,
);
}
fieldNames.add(name);
});
const ty = typeOfItem(item.id, item.span) as TyStruct;
const ty = typeOfItem(item.id, item.span) as TyStruct;
return {
...item,
node: {
name: item.node.name,
fields: item.node.fields.map((field, i) => ({
name: field.name,
type: {
...field.type,
ty: ty.fields[i][1],
return {
...item,
node: {
name: item.node.name,
type: {
kind: "struct",
fields: item.node.type.fields.map((field, i) => ({
name: field.name,
type: {
...field.type,
ty: ty.fields[i][1],
},
})),
},
},
})),
},
};
};
}
case "alias": {
return {
...item,
node: {
name: item.node.name,
type: {
kind: "alias",
type: item.node.type.type,
},
},
};
}
}
}
case "mod": {
return {