write prInt

This commit is contained in:
nora 2023-07-30 23:05:57 +02:00
parent d9868e3111
commit 7f65dc0277
8 changed files with 155 additions and 40 deletions

25
opt.wat
View file

@ -1,25 +0,0 @@
(module
(type (;0;) (func (param i32 i32 i32 i32) (result i32)))
(type (;1;) (func))
(import "wasi_snapshot_preview1" "fd_write" (func (;0;) (type 0)))
(func (;1;) (type 1)
i32.const 1028
i32.const 0
i32.store
i32.const 1032
i32.const 2
i32.store
i32.const 1
i32.const 1028
i32.const 2
i32.const 1024
call 0
drop
)
(table (;0;) 0 0 funcref)
(memory (;0;) 65536 65536)
(export "memory" (memory 0))
(export "__indirect_function_table" (table 0))
(export "_start" (func 1))
(data (;0;) (i32.const 0) "a\0a")
)

View file

@ -300,6 +300,7 @@ export const BUILTINS = [
"Bool",
"true",
"false",
"trap",
// Intrinsics:
"__i32_store",
"__i64_store",

View file

@ -47,16 +47,17 @@ function renderError(input: string, e: CompilerError) {
throw Error(`Span out of bounds: ${e.span.start}..${e.span.end}`);
}
const lineIdx = lineSpans.indexOf(line);
const lineNo = lineIdx + 1;
console.error(`error: ${e.message}`);
console.error(`${lineIdx} | ${spanToSnippet(input, line)}`);
console.error(`${lineNo} | ${spanToSnippet(input, line)}`);
const startRelLine =
e.span.start === Number.MAX_SAFE_INTEGER ? 0 : e.span.start - line.start;
const spanLength = min(e.span.end, line.end) - e.span.start;
console.error(
`${" ".repeat(String(lineIdx).length)} ${" ".repeat(
`${" ".repeat(String(lineNo).length)} ${" ".repeat(
startRelLine
)}${"^".repeat(spanLength)}`
);

View file

@ -9,23 +9,84 @@ import { writeModuleWatToString } from "./wasm/wat";
import fs from "fs";
import { exec } from "child_process";
const input = `
const INPUT = `
function main() = (
prInt(0);
prInt(1);
prInt(9);
prInt(10);
prInt(100);
prIntln(0);
prIntln(1);
prIntln(9);
prIntln(2352353);
prIntln(100);
);
function prInt(a: Int) = (
function prIntln(x: Int) = (
prInt(x);
print("\n");
);
function uwu(): (Int, Int) = (0, 0);
function stringForDigit(x: Int): String =
if x == 0 then "0"
else if x == 1 then "1"
else if x == 2 then "2"
else if x == 3 then "3"
else if x == 4 then "4"
else if x == 5 then "5"
else if x == 6 then "6"
else if x == 7 then "7"
else if x == 8 then "8"
else if x == 9 then "9"
else trap();
function log10(x: Int): Int = (
let i = 0;
loop (
if x < 10 then break;
i = i + 1;
x = x / 10;
);
i
);
function pow(base: Int, exp: Int): Int = (
let acc = 1;
loop (
if exp == 0 then break;
acc = acc * base;
exp = exp - 1;
);
acc
);
function prInt(x: Int) = (
let mag = log10(x);
loop (
if mag == 0 then break;
let base = pow(10, mag);
let digit = x / base;
print(stringForDigit(digit));
x = x % base;
mag = mag - 1;
);
print(stringForDigit(x % 10));
);
function println(s: String) = (
print(s);
print("\n");
);
`;
function main() {
let input: string;
if (process.argv.length > 2) {
input = fs.readFileSync(process.argv[2], { encoding: "utf-8" });
} else {
input = INPUT;
}
withErrorHandler(input, () => {
const start = Date.now();

View file

@ -203,6 +203,7 @@ type FuncContext = {
cx: Context;
item: Item;
func: FunctionDef;
wasmType: wasm.FuncType;
wasm: wasm.Func;
varLocations: VarLocation[];
loopDepths: Map<LoopId, number>;
@ -231,6 +232,7 @@ function lowerFunc(cx: Context, item: Item, func: FunctionDef) {
cx,
item,
func,
wasmType,
wasm: wasmFunc,
varLocations: paramLocations,
loopDepths: new Map(),
@ -265,7 +267,7 @@ function lowerExpr(fcx: FuncContext, instrs: wasm.Instr[], expr: Expr) {
lowerExpr(fcx, instrs, expr.rhs);
const types = wasmTypeForBody(expr.rhs.ty!);
const local = fcx.wasm.locals.length;
const local = fcx.wasm.locals.length + fcx.wasmType.params.length;
fcx.wasm.locals.push(...types);
@ -498,6 +500,10 @@ function lowerExpr(fcx: FuncContext, instrs: wasm.Instr[], expr: Expr) {
if (expr.lhs.value.res!.kind === "builtin") {
switch (expr.lhs.value.res!.name) {
case "trap": {
instrs.push({ kind: "unreachable" });
break exprKind;
}
case "__i32_load": {
lowerExpr(fcx, instrs, expr.args[0]);
instrs.push({ kind: "i64.load", imm: {} });

View file

@ -61,6 +61,8 @@ function typeOfBuiltinValue(name: BuiltinName, span: Span): Ty {
return TY_BOOL;
case "print":
return mkTyFn([TY_STRING], TY_UNIT);
case "trap":
return mkTyFn([], TY_NEVER);
case "__i32_store":
return mkTyFn([TY_I32, TY_I32], TY_UNIT);
case "__i64_store":

View file

@ -541,11 +541,13 @@ function printImport(import_: Import, f: Formatter) {
});
}
function printFunction(func: Func, f: Formatter) {
function printFunction(func: Func, idx: number, f: Formatter) {
f.sexpr(() => {
f.keyword("func");
printId(func._name, f);
f.word(`(;${idx};)`, chalk.gray);
f.sexpr(() => {
f.keyword("type");
f.type(func.type);
@ -678,9 +680,9 @@ function printModule(module: Module, f: Formatter) {
printImport(import_, f);
});
module.funcs.forEach((func) => {
module.funcs.forEach((func, i) => {
breakIfAny();
printFunction(func, f);
printFunction(func, i + module.imports.length, f);
});
module.tables.forEach((table) => {

67
test.nil Normal file
View file

@ -0,0 +1,67 @@
function main() = (
prIntln(0);
prIntln(1);
prIntln(9);
prIntln(2352353);
prIntln(100);
);
function prIntln(x: Int) = (
prInt(x);
print("\n");
);
function stringForDigit(x: Int): String =
if x == 0 then "0"
else if x == 1 then "1"
else if x == 2 then "2"
else if x == 3 then "3"
else if x == 4 then "4"
else if x == 5 then "5"
else if x == 6 then "6"
else if x == 7 then "7"
else if x == 8 then "8"
else if x == 9 then "9"
else trap();
function log10(x: Int): Int = (
let i = 0;
loop (
if x < 10 then break;
i = i + 1;
x = x / 10;
);
i
);
function pow(base: Int, exp: Int): Int = (
let acc = 1;
loop (
if exp == 0 then break;
acc = acc * base;
exp = exp - 1;
);
acc
);
function prInt(x: Int) = (
let mag = log10(x);
loop (
if mag == 0 then break;
let base = pow(10, mag);
let digit = x / base;
print(stringForDigit(digit));
x = x % base;
mag = mag - 1;
);
print(stringForDigit(x % 10));
);
function println(s: String) = (
print(s);
print("\n");
);