rework mir pretty colors
All checks were successful
Check / Explore-Gitea-Actions (push) Successful in 10s
All checks were successful
Check / Explore-Gitea-Actions (push) Successful in 10s
This commit is contained in:
parent
c5c09eb10e
commit
6bb68863ca
52
src/main.ts
52
src/main.ts
@ -4,6 +4,7 @@ import * as front from "./front/mod.ts";
|
|||||||
import * as middle from "./middle.ts";
|
import * as middle from "./middle.ts";
|
||||||
import * as mir from "./mir.ts";
|
import * as mir from "./mir.ts";
|
||||||
import { FnInterpreter } from "./mir_interpreter.ts";
|
import { FnInterpreter } from "./mir_interpreter.ts";
|
||||||
|
import * as stringify from "./stringify.ts";
|
||||||
|
|
||||||
const reporter = new Reporter();
|
const reporter = new Reporter();
|
||||||
|
|
||||||
@ -40,58 +41,9 @@ if (!mainFn) {
|
|||||||
const m = new middle.MiddleLowerer(syms, tys);
|
const m = new middle.MiddleLowerer(syms, tys);
|
||||||
const mainMiddleFn = m.lowerFn(mainFn);
|
const mainMiddleFn = m.lowerFn(mainFn);
|
||||||
|
|
||||||
function printMirFn(fn: mir.Fn) {
|
|
||||||
const pretty = fn.pretty();
|
|
||||||
const [lines, colors] = pretty
|
|
||||||
.split("\n")
|
|
||||||
.map<[string, string[]]>((line) => [line, []])
|
|
||||||
.map<[string, string[]]>(([line, colors]) => {
|
|
||||||
line = line.replace(/%\d+/g, "__$&__");
|
|
||||||
line = line.replace(/"(?:[^"\\]|\\.)*"/g, "__$&__");
|
|
||||||
if (/^\s*__%\d+__ \(.*?\) =/.test(line)) {
|
|
||||||
line = line.replace(
|
|
||||||
/__%(\d+)__ \((.*?)\) =/g,
|
|
||||||
"%c%$1 %c($2)%c =",
|
|
||||||
);
|
|
||||||
colors.push("color: lightblue;", "color: gray;", "");
|
|
||||||
}
|
|
||||||
if (/[A-Z][a-zA-Z]+/.test(line)) {
|
|
||||||
line = line.replace(/([A-Z][a-zA-Z]+)/, "%c$1%c");
|
|
||||||
colors.push("color: red; font-weight: bold;", "");
|
|
||||||
}
|
|
||||||
if (/\bptr\b/.test(line)) {
|
|
||||||
line = line.replace(/\b(ptr)\b/, "%c$1%c");
|
|
||||||
colors.push("color: gray;", "");
|
|
||||||
}
|
|
||||||
while (true) {
|
|
||||||
if (/__%\d+__/.test(line)) {
|
|
||||||
line = line.replace(/__%(\d+)__/, "%c%$1%c");
|
|
||||||
colors.push("color: lightblue;", "");
|
|
||||||
} else if (/__"(?:[^"\\]|\\.)*"__/.test(line)) {
|
|
||||||
line = line.replace(/__("(?:[^"\\]|\\.)*")__/, "%c$1%c");
|
|
||||||
colors.push("color: green;", "");
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return [line, colors];
|
|
||||||
})
|
|
||||||
.reduce<[string[], string[]]>(
|
|
||||||
([linesAcc, colorsAcc], [line, colors]) => {
|
|
||||||
linesAcc.push(line);
|
|
||||||
colorsAcc.push(...colors);
|
|
||||||
return [linesAcc, colorsAcc];
|
|
||||||
},
|
|
||||||
[[], []],
|
|
||||||
);
|
|
||||||
const text = lines.join("\n");
|
|
||||||
console.log(text + "%c", ...colors, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Deno.args.includes("--print-mir")) {
|
if (Deno.args.includes("--print-mir")) {
|
||||||
for (const fn of m.allFns()) {
|
for (const fn of m.allFns()) {
|
||||||
printMirFn(fn);
|
stringify.printWithConsoleColors(fn.pretty(stringify.consoleColors));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -22,8 +22,8 @@ export class Fn {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pretty(): string {
|
pretty(colors?: stringify.PrettyColors): string {
|
||||||
return stringify.mirFnPretty(this);
|
return stringify.mirFnPretty(this, colors);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
203
src/stringify.ts
203
src/stringify.ts
@ -1,48 +1,114 @@
|
|||||||
import * as ty from "./ty.ts";
|
import * as ty from "./ty.ts";
|
||||||
import * as mir from "./mir.ts";
|
import * as mir from "./mir.ts";
|
||||||
|
|
||||||
export function tyPretty(ty: ty.Ty): string {
|
export type PrettyColors = {
|
||||||
|
punctuation: string;
|
||||||
|
operator: string;
|
||||||
|
literal: string;
|
||||||
|
string: string;
|
||||||
|
keyword: string;
|
||||||
|
varIdent: string;
|
||||||
|
fnIdent: string;
|
||||||
|
typeIdent: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const noColors: PrettyColors = {
|
||||||
|
punctuation: "",
|
||||||
|
operator: "",
|
||||||
|
literal: "",
|
||||||
|
string: "",
|
||||||
|
keyword: "",
|
||||||
|
varIdent: "",
|
||||||
|
fnIdent: "",
|
||||||
|
typeIdent: "",
|
||||||
|
};
|
||||||
|
|
||||||
|
export const consoleColors: PrettyColors = {
|
||||||
|
punctuation: "\x1bpunctuation",
|
||||||
|
operator: "\x1boperator",
|
||||||
|
literal: "\x1bliteral",
|
||||||
|
string: "\x1bstring",
|
||||||
|
keyword: "\x1bkeyword",
|
||||||
|
varIdent: "\x1bvarIdent",
|
||||||
|
fnIdent: "\x1bfnIdent",
|
||||||
|
typeIdent: "\x1btypeIdent",
|
||||||
|
};
|
||||||
|
|
||||||
|
export function printWithConsoleColors(str: string) {
|
||||||
|
const keys = Object.keys(consoleColors).join("|");
|
||||||
|
const pat = new RegExp(`\x1b(${keys})`, "g");
|
||||||
|
const matches = str.matchAll(pat).toArray();
|
||||||
|
|
||||||
|
const replacers: Record<string, string> = {
|
||||||
|
punctuation: "color: gray;",
|
||||||
|
operator: "color: #fb4934;",
|
||||||
|
literal: "color: pink;",
|
||||||
|
string: "color: green;",
|
||||||
|
keyword: "color: blue;",
|
||||||
|
varIdent: "color: lightblue;",
|
||||||
|
fnIdent: "color: green; font-weight: bold;",
|
||||||
|
typeIdent: "color: yellow;",
|
||||||
|
};
|
||||||
|
|
||||||
|
const colorArgs: string[] = [];
|
||||||
|
|
||||||
|
for (const match of matches) {
|
||||||
|
str = str.replace(match[0], "%c");
|
||||||
|
colorArgs.push(replacers[match[1]]);
|
||||||
|
}
|
||||||
|
str += "%c";
|
||||||
|
colorArgs.push("");
|
||||||
|
|
||||||
|
console.log(str, ...colorArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function tyPretty(ty: ty.Ty, colors = noColors): string {
|
||||||
|
const c = colors;
|
||||||
switch (ty.kind.tag) {
|
switch (ty.kind.tag) {
|
||||||
case "Error":
|
case "Error":
|
||||||
return "<error>";
|
return `<error>`;
|
||||||
case "Void":
|
case "Void":
|
||||||
return "void";
|
return `${c.typeIdent}void`;
|
||||||
case "IntLiteral":
|
case "IntLiteral":
|
||||||
return "{integer}";
|
return `${c.typeIdent}{integer}`;
|
||||||
case "Int":
|
case "Int":
|
||||||
return `${ty.kind.intTy}`;
|
return `${c.typeIdent}${ty.kind.intTy}`;
|
||||||
case "Bool":
|
case "Bool":
|
||||||
return "bool";
|
return `${c.typeIdent}bool`;
|
||||||
case "Ptr":
|
case "Ptr":
|
||||||
return `*${ty.kind.ty.pretty()}`;
|
return `${c.punctuation}*${ty.kind.ty.pretty(c)}`;
|
||||||
case "PtrMut":
|
case "PtrMut":
|
||||||
return `*mut ${ty.kind.ty.pretty()}`;
|
return `${c.punctuation}*${c.keyword}mut ${ty.kind.ty.pretty(c)}`;
|
||||||
case "Array":
|
case "Array":
|
||||||
return `[${ty.kind.ty.pretty()}; ${ty.kind.length}]`;
|
return `${c.punctuation}[${
|
||||||
|
ty.kind.ty.pretty(c)
|
||||||
|
}${c.punctuation}; ${ty.kind.length}${c.punctuation}]`;
|
||||||
case "Slice":
|
case "Slice":
|
||||||
return `[${ty.kind.ty.pretty()}]`;
|
return `${c.punctuation}[${ty.kind.ty.pretty(c)}${c.punctuation}]`;
|
||||||
case "Range":
|
case "Range":
|
||||||
return `Range`;
|
return `${c.typeIdent}Range`;
|
||||||
case "Fn":
|
case "Fn":
|
||||||
return `fn (${
|
return `${c.keyword}fn ${c.punctuation}(${
|
||||||
ty.kind.params.map((param) => param.pretty()).join(", ")
|
ty.kind.params.map((param) => param.pretty(c)).join(
|
||||||
}) -> ${ty.kind.retTy.pretty()}`;
|
`${c.punctuation}, `,
|
||||||
|
)
|
||||||
|
}${c.punctuation}) -> ${ty.kind.retTy.pretty(c)}`;
|
||||||
case "FnStmt":
|
case "FnStmt":
|
||||||
if (!ty.kind.ty.is("Fn")) {
|
if (!ty.kind.ty.is("Fn")) {
|
||||||
throw new Error();
|
throw new Error();
|
||||||
}
|
}
|
||||||
return `fn ${ty.kind.stmt.kind.ident}(${
|
return `${c.keyword}fn ${ty.kind.stmt.kind.ident}(${
|
||||||
ty.kind.ty.kind.params.map((param) => param.pretty())
|
ty.kind.ty.kind.params.map((param) => param.pretty(c))
|
||||||
.join(
|
.join(
|
||||||
", ",
|
`${c.punctuation}, `,
|
||||||
)
|
)
|
||||||
}) -> ${ty.kind.ty.kind.retTy.pretty()}`;
|
}${c.punctuation}) -> ${ty.kind.ty.kind.retTy.pretty(c)}`;
|
||||||
}
|
}
|
||||||
return "<unhandled>";
|
return "<unhandled>";
|
||||||
}
|
}
|
||||||
|
|
||||||
export function mirFnPretty(fn: mir.Fn): string {
|
export function mirFnPretty(fn: mir.Fn, colors = noColors): string {
|
||||||
return new MirFnPrettyStringifier(fn).stringify();
|
return new MirFnPrettyStringifier(fn, colors).stringify();
|
||||||
}
|
}
|
||||||
|
|
||||||
class MirFnPrettyStringifier {
|
class MirFnPrettyStringifier {
|
||||||
@ -52,9 +118,12 @@ class MirFnPrettyStringifier {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private fn: mir.Fn,
|
private fn: mir.Fn,
|
||||||
|
private colors: PrettyColors,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
stringify(): string {
|
stringify(): string {
|
||||||
|
const c = this.colors;
|
||||||
|
|
||||||
const fnTy = this.fn.ty.is("FnStmt") && this.fn.ty.kind.ty.is("Fn")
|
const fnTy = this.fn.ty.is("FnStmt") && this.fn.ty.kind.ty.is("Fn")
|
||||||
? this.fn.ty.kind.ty
|
? this.fn.ty.kind.ty
|
||||||
: null;
|
: null;
|
||||||
@ -65,21 +134,28 @@ class MirFnPrettyStringifier {
|
|||||||
const ident = this.fn.stmt.kind.ident;
|
const ident = this.fn.stmt.kind.ident;
|
||||||
|
|
||||||
const params = fnTy.kind.params
|
const params = fnTy.kind.params
|
||||||
.map((ty, idx) => `${idx}: ${ty.pretty()}`)
|
.map((ty, idx) =>
|
||||||
.join(", ");
|
`${c.varIdent}${idx}${c.punctuation}: ${ty.pretty(c)}`
|
||||||
const retTy = fnTy.kind.retTy.pretty();
|
)
|
||||||
|
.join(`${c.punctuation}, `);
|
||||||
|
const retTy = fnTy.kind.retTy.pretty(c);
|
||||||
|
|
||||||
this.result += `fn ${ident}(${params}) -> ${retTy} {\n`;
|
this.result +=
|
||||||
|
`${c.keyword}fn ${c.fnIdent}${ident}${c.punctuation}(${params}${c.punctuation}) -> ${retTy} ${c.punctuation}{\n`;
|
||||||
|
|
||||||
for (const bb of this.fn.bbs) {
|
for (const bb of this.fn.bbs) {
|
||||||
this.basicBlock(bb);
|
this.basicBlock(bb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.result += `${c.punctuation}}`;
|
||||||
|
|
||||||
return this.result;
|
return this.result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private basicBlock(bb: mir.BasicBlock) {
|
private basicBlock(bb: mir.BasicBlock) {
|
||||||
this.result += `bb${this.bbId(bb)}:\n`;
|
const c = this.colors;
|
||||||
|
|
||||||
|
this.result += `${c.varIdent}bb${this.bbId(bb)}${c.punctuation}:\n`;
|
||||||
|
|
||||||
for (const inst of bb.insts) {
|
for (const inst of bb.insts) {
|
||||||
this.inst(inst);
|
this.inst(inst);
|
||||||
@ -93,15 +169,19 @@ class MirFnPrettyStringifier {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const c = this.colors;
|
||||||
|
|
||||||
// inst is a value
|
// inst is a value
|
||||||
const expr = (tail: string) => {
|
const expr = (tail: string) => {
|
||||||
this.result += ` %${
|
this.result += ` ${c.varIdent}%${
|
||||||
this.instId(inst)
|
this.instId(inst)
|
||||||
} (${inst.ty.pretty()}) = ${inst.kind.tag}${tail}\n`;
|
}${c.punctuation}: ${
|
||||||
|
inst.ty.pretty(c)
|
||||||
|
}${c.punctuation} = ${c.operator}${inst.kind.tag}${tail}\n`;
|
||||||
};
|
};
|
||||||
// inst is a statement
|
// inst is a statement
|
||||||
const stmt = (tail: string) => {
|
const stmt = (tail: string) => {
|
||||||
this.result += ` ${inst.kind.tag}${tail}\n`;
|
this.result += ` ${c.operator}${inst.kind.tag}${tail}\n`;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.instTail(inst, expr, stmt);
|
this.instTail(inst, expr, stmt);
|
||||||
@ -110,19 +190,21 @@ class MirFnPrettyStringifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private instArg(inst: mir.Inst): string {
|
private instArg(inst: mir.Inst): string {
|
||||||
|
const c = this.colors;
|
||||||
|
|
||||||
const inline: mir.InstKind["tag"][] = ["Void", "Int", "Bool", "Array"];
|
const inline: mir.InstKind["tag"][] = ["Void", "Int", "Bool", "Array"];
|
||||||
if (
|
if (
|
||||||
inline.includes(inst.kind.tag) &&
|
inline.includes(inst.kind.tag) &&
|
||||||
!this.instsPrinted.has(inst)
|
!this.instsPrinted.has(inst)
|
||||||
) {
|
) {
|
||||||
let str = `${inst.kind.tag}`;
|
let str = `${c.operator}${inst.kind.tag}`;
|
||||||
this.instTail(inst, (s) => {
|
this.instTail(inst, (s) => {
|
||||||
str += s;
|
str += s;
|
||||||
}, () => {});
|
}, () => {});
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
this.inst(inst);
|
this.inst(inst);
|
||||||
return `%${this.instId(inst)}`;
|
return `${c.varIdent}%${this.instId(inst)}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private instTail(
|
private instTail(
|
||||||
@ -130,6 +212,7 @@ class MirFnPrettyStringifier {
|
|||||||
expr: (str: string) => void,
|
expr: (str: string) => void,
|
||||||
stmt: (str: string) => void,
|
stmt: (str: string) => void,
|
||||||
) {
|
) {
|
||||||
|
const c = this.colors;
|
||||||
const r = (inst: mir.Inst) => this.instArg(inst);
|
const r = (inst: mir.Inst) => this.instArg(inst);
|
||||||
|
|
||||||
const k = inst.kind;
|
const k = inst.kind;
|
||||||
@ -139,38 +222,66 @@ class MirFnPrettyStringifier {
|
|||||||
case "Void":
|
case "Void":
|
||||||
return expr(``);
|
return expr(``);
|
||||||
case "Int":
|
case "Int":
|
||||||
return expr(` ${k.value}${k.intTy}`);
|
return expr(` ${c.literal}${k.value}${k.intTy}`);
|
||||||
case "Bool":
|
case "Bool":
|
||||||
return expr(` ${k.value}`);
|
return expr(` ${c.literal}${k.value}`);
|
||||||
case "Str":
|
case "Str":
|
||||||
return expr(` ${JSON.stringify(k.value)}`);
|
return expr(` ${c.string}${JSON.stringify(k.value)}`);
|
||||||
case "Array":
|
case "Array":
|
||||||
return expr(` [${k.values.map(r).join(", ")}]`);
|
return expr(
|
||||||
|
` ${c.punctuation}[${
|
||||||
|
k.values.map(r).join(`${c.punctuation}, `)
|
||||||
|
}${c.punctuation}]`,
|
||||||
|
);
|
||||||
case "Fn":
|
case "Fn":
|
||||||
return expr(` ${k.fn.stmt.kind.ident}`);
|
return expr(` ${c.fnIdent}${k.fn.stmt.kind.ident}`);
|
||||||
case "Param":
|
case "Param":
|
||||||
return expr(` ${k.idx}`);
|
return expr(` ${c.varIdent}${k.idx}`);
|
||||||
case "GetElemPtr":
|
case "GetElemPtr":
|
||||||
return expr(` &(ptr ${r(k.base)})[${r(k.offset)}]`);
|
return expr(
|
||||||
|
` ${c.punctuation}&(${c.keyword}ptr ${
|
||||||
|
r(k.base)
|
||||||
|
}${c.punctuation})[${r(k.offset)}${c.punctuation}]`,
|
||||||
|
);
|
||||||
case "Slice":
|
case "Slice":
|
||||||
return expr(
|
return expr(
|
||||||
` &[ptr ${r(k.value)}][${k.begin ? r(k.begin) : ""}..${
|
` ${c.punctuation}&(${c.keyword}ptr ${
|
||||||
|
r(k.value)
|
||||||
|
}${c.punctuation})[${
|
||||||
|
k.begin ? r(k.begin) : ""
|
||||||
|
}${c.punctuation}..${
|
||||||
k.end ? r(k.end) : ""
|
k.end ? r(k.end) : ""
|
||||||
}]`,
|
}${c.punctuation}]`,
|
||||||
);
|
);
|
||||||
case "Call":
|
case "Call":
|
||||||
return expr(` ${r(k.callee)} (${k.args.map(r).join(", ")})`);
|
return expr(
|
||||||
|
` ${r(k.callee)} ${c.punctuation}(${
|
||||||
|
k.args.map(r).join(`${c.punctuation}, `)
|
||||||
|
}${c.punctuation})`,
|
||||||
|
);
|
||||||
case "Alloca":
|
case "Alloca":
|
||||||
return expr(``);
|
return expr(``);
|
||||||
case "Load":
|
case "Load":
|
||||||
return expr(` [ptr ${r(k.source)}]`);
|
return expr(
|
||||||
|
` ${c.punctuation}[${c.keyword}ptr ${
|
||||||
|
r(k.source)
|
||||||
|
}${c.punctuation}]`,
|
||||||
|
);
|
||||||
case "Store":
|
case "Store":
|
||||||
return stmt(` [ptr ${r(k.target)}] = ${r(k.source)}`);
|
return stmt(
|
||||||
|
` ${c.punctuation}[${c.keyword}ptr ${
|
||||||
|
r(k.target)
|
||||||
|
}${c.punctuation}] = ${r(k.source)}`,
|
||||||
|
);
|
||||||
case "Jump":
|
case "Jump":
|
||||||
return stmt(` bb${this.bbId(k.target)}`);
|
return stmt(` ${c.varIdent}bb${this.bbId(k.target)}`);
|
||||||
case "Branch":
|
case "Branch":
|
||||||
return stmt(
|
return stmt(
|
||||||
` if ${r(k.cond)}: bb${this.bbId(k.truthy)}, else: bb${
|
` ${c.keyword}if ${
|
||||||
|
r(k.cond)
|
||||||
|
}${c.punctuation}: ${c.varIdent}bb${
|
||||||
|
this.bbId(k.truthy)
|
||||||
|
}${c.punctuation}, ${c.keyword}else${c.punctuation}: ${c.varIdent}bb${
|
||||||
this.bbId(k.falsy)
|
this.bbId(k.falsy)
|
||||||
}`,
|
}`,
|
||||||
);
|
);
|
||||||
@ -195,11 +306,11 @@ class MirFnPrettyStringifier {
|
|||||||
case "Mul":
|
case "Mul":
|
||||||
case "Div":
|
case "Div":
|
||||||
case "Rem":
|
case "Rem":
|
||||||
return expr(` ${r(k.left)}, ${r(k.right)}`);
|
return expr(` ${r(k.left)}${c.punctuation}, ${r(k.right)}`);
|
||||||
case "Len":
|
case "Len":
|
||||||
return expr(` ${r(k.source)}`);
|
return expr(` ${r(k.source)}`);
|
||||||
case "DebugPrint":
|
case "DebugPrint":
|
||||||
return stmt(` ${k.args.map(r).join(", ")}`);
|
return stmt(` ${k.args.map(r).join(`${c.punctuation}, `)}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user