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", "Bool",
"true", "true",
"false", "false",
"trap",
// Intrinsics: // Intrinsics:
"__i32_store", "__i32_store",
"__i64_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}`); throw Error(`Span out of bounds: ${e.span.start}..${e.span.end}`);
} }
const lineIdx = lineSpans.indexOf(line); const lineIdx = lineSpans.indexOf(line);
const lineNo = lineIdx + 1;
console.error(`error: ${e.message}`); console.error(`error: ${e.message}`);
console.error(`${lineIdx} | ${spanToSnippet(input, line)}`); console.error(`${lineNo} | ${spanToSnippet(input, line)}`);
const startRelLine = const startRelLine =
e.span.start === Number.MAX_SAFE_INTEGER ? 0 : e.span.start - line.start; e.span.start === Number.MAX_SAFE_INTEGER ? 0 : e.span.start - line.start;
const spanLength = min(e.span.end, line.end) - e.span.start; const spanLength = min(e.span.end, line.end) - e.span.start;
console.error( console.error(
`${" ".repeat(String(lineIdx).length)} ${" ".repeat( `${" ".repeat(String(lineNo).length)} ${" ".repeat(
startRelLine startRelLine
)}${"^".repeat(spanLength)}` )}${"^".repeat(spanLength)}`
); );

View file

@ -9,23 +9,84 @@ import { writeModuleWatToString } from "./wasm/wat";
import fs from "fs"; import fs from "fs";
import { exec } from "child_process"; import { exec } from "child_process";
const input = ` const INPUT = `
function main() = ( function main() = (
prInt(0); prIntln(0);
prInt(1); prIntln(1);
prInt(9); prIntln(9);
prInt(10); prIntln(2352353);
prInt(100); 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() { function main() {
let input: string;
if (process.argv.length > 2) {
input = fs.readFileSync(process.argv[2], { encoding: "utf-8" });
} else {
input = INPUT;
}
withErrorHandler(input, () => { withErrorHandler(input, () => {
const start = Date.now(); const start = Date.now();

View file

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

View file

@ -61,6 +61,8 @@ function typeOfBuiltinValue(name: BuiltinName, span: Span): Ty {
return TY_BOOL; return TY_BOOL;
case "print": case "print":
return mkTyFn([TY_STRING], TY_UNIT); return mkTyFn([TY_STRING], TY_UNIT);
case "trap":
return mkTyFn([], TY_NEVER);
case "__i32_store": case "__i32_store":
return mkTyFn([TY_I32, TY_I32], TY_UNIT); return mkTyFn([TY_I32, TY_I32], TY_UNIT);
case "__i64_store": 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.sexpr(() => {
f.keyword("func"); f.keyword("func");
printId(func._name, f); printId(func._name, f);
f.word(`(;${idx};)`, chalk.gray);
f.sexpr(() => { f.sexpr(() => {
f.keyword("type"); f.keyword("type");
f.type(func.type); f.type(func.type);
@ -678,9 +680,9 @@ function printModule(module: Module, f: Formatter) {
printImport(import_, f); printImport(import_, f);
}); });
module.funcs.forEach((func) => { module.funcs.forEach((func, i) => {
breakIfAny(); breakIfAny();
printFunction(func, f); printFunction(func, i + module.imports.length, f);
}); });
module.tables.forEach((table) => { 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");
);