make it a wasi executable

This commit is contained in:
nora 2023-07-26 21:35:31 +02:00
parent 8dd7c174ee
commit 1d0e3a3aff
7 changed files with 87 additions and 13 deletions

View file

@ -1,6 +1,6 @@
import { Span } from "./error";
export type Ast = Item[];
export type Ast = { items: Item[]; typeckResults?: TypeckResults };
export type Identifier = {
name: string;
@ -273,6 +273,10 @@ export const TY_STRING: Ty = { kind: "string" };
export const TY_BOOL: Ty = { kind: "bool" };
export const TY_INT: Ty = { kind: "int", signed: false };
export type TypeckResults = {
main: ItemId;
};
// folders
export type FoldFn<T> = (value: T) => T;
@ -300,7 +304,10 @@ export const DEFAULT_FOLDER: Folder = {
};
export function foldAst(ast: Ast, folder: Folder): Ast {
return ast.map((item) => folder.item(item));
return {
items: ast.items.map((item) => folder.item(item)),
typeckResults: ast.typeckResults,
};
}
export function superFoldItem(item: Item, folder: Folder): Item {

View file

@ -10,7 +10,8 @@ import fs from "fs";
import { exec } from "child_process";
const input = `
function main(i: Int, j: Int): Bool = false == (i == 0);
function main() = ();
function test(i: Int, j: Int): Bool = false == (i == 0);
`;
function main() {

View file

@ -1,9 +1,10 @@
import { AST } from "prettier";
import { Ast, Expr, FunctionDef, Item, Ty, TyFn, varUnreachable } from "./ast";
import * as wasm from "./wasm/defs";
type StringifiedForMap<T> = string;
type Context = {
export type Context = {
mod: wasm.Module;
funcTypes: Map<StringifiedForMap<wasm.FuncType>, wasm.TypeIdx>;
funcIndices: Map<number, wasm.FuncIdx>;
@ -34,9 +35,21 @@ export function lower(ast: Ast): wasm.Module {
exports: [],
};
mod.mems.push({ _name: "memory", type: { min: 1024, max: 1024 } });
mod.exports.push({ name: "memory", desc: { kind: "memory", idx: 0 } });
mod.tables.push({
_name: "__indirect_function_table",
type: { limits: { min: 0, max: 0 }, reftype: "funcref" },
});
mod.exports.push({
name: "__indirect_function_table",
desc: { kind: "table", idx: 0 },
});
const cx: Context = { mod, funcTypes: new Map(), funcIndices: new Map() };
ast.forEach((item) => {
ast.items.forEach((item) => {
switch (item.kind) {
case "function": {
lowerFunc(cx, item, item.node);
@ -44,6 +57,8 @@ export function lower(ast: Ast): wasm.Module {
}
});
addRt(cx, ast);
return mod;
}
@ -384,6 +399,26 @@ function todo(msg: string): never {
throw new Error(`TODO: ${msg}`);
}
function exists<T>(val: T | undefined): val is T {
return val !== undefined;
// Make the program runnable using wasi-preview-1
function addRt(cx: Context, ast: Ast) {
const { mod } = cx;
console.log(cx.funcIndices);
const main = cx.funcIndices.get(ast.typeckResults!.main);
if (main === undefined) {
throw new Error(`main function (${main}) was not compiled.`);
}
const start: wasm.Func = {
_name: "_start",
type: internFuncType(cx, { params: [], returns: [] }),
locals: [],
body: [{ kind: "call", func: main }],
};
const startIdx = mod.funcs.length;
mod.funcs.push(start);
mod.exports.push({ name: "_start", desc: { kind: "func", idx: startIdx } });
}

View file

@ -29,7 +29,7 @@ export function parse(t: Token[]): Ast {
const withIds = items.map((item, i) => ({ ...item, id: i }));
return withIds;
return { items: withIds };
}
function parseItem(t: Token[]): [Token[], Item] {

View file

@ -11,7 +11,7 @@ import {
} from "./ast";
export function printAst(ast: Ast): string {
return ast.map(printItem).join("\n");
return ast.items.map(printItem).join("\n");
}
function printItem(item: Item): string {

View file

@ -17,8 +17,8 @@ const BUILTIN_SET = new Set<string>(BUILTINS);
export function resolve(ast: Ast): Ast {
const items = new Map<string, number>();
for (let i = 0; i < ast.length; i++) {
const item = ast[i];
for (let i = 0; i < ast.items.length; i++) {
const item = ast.items[i];
const existing = items.get(item.node.name);
if (existing !== undefined) {
throw new CompilerError(

View file

@ -102,7 +102,7 @@ export function typeck(ast: Ast): Ast {
throw Error(`cycle computing type of #G${index}`);
}
itemTys.set(index, null);
const item = ast[index];
const item = ast.items[index];
switch (item.kind) {
case "function": {
const args = item.node.params.map((arg) => lowerAstTy(arg.type));
@ -168,7 +168,38 @@ export function typeck(ast: Ast): Ast {
},
};
return foldAst(ast, checker);
const typecked = foldAst(ast, checker);
const main = typecked.items.find((item) => {
if (item.kind === "function" && item.node.name === "main") {
const func = item.node;
if (func.returnType !== undefined) {
const ty = func.returnType.ty!;
if (ty.kind !== "tuple" || ty.elems.length !== 0) {
throw new CompilerError(
`\`main\` has an invalid signature. main takes no arguments and returns nothing`,
item.span
);
}
}
return true;
}
return false;
});
if (!main) {
throw new CompilerError(`\`main\` function not found`, {
start: 0,
end: 1,
});
}
typecked.typeckResults = {
main: main.id,
};
return typecked;
}
type TyVarRes =