web, runtime, compiler, connections

This commit is contained in:
SimonFJ20 2024-11-21 12:08:07 +01:00
parent 7806b64783
commit af8ce1d47a
6 changed files with 170 additions and 11 deletions

14
compiler/mod.ts Normal file
View File

@ -0,0 +1,14 @@
import { Stmt } from "./ast.ts";
import { Lexer } from "./Lexer.ts";
import { Parser } from "./Parser.ts";
export * from "./Parser.ts";
export * from "./ast.ts";
export * from "./arch.ts";
export * from "./Lexer.ts";
export * from "./Token.ts";
export async function compileWithDebug(filepath: string): Promise<Stmt[]> {
const text = await Deno.readTextFile(filepath);
return new Parser(new Lexer(text)).parseStmts();
}

View File

@ -6,6 +6,7 @@
"jsr:@std/assert@1": "1.0.8", "jsr:@std/assert@1": "1.0.8",
"jsr:@std/bytes@1": "1.0.4", "jsr:@std/bytes@1": "1.0.4",
"jsr:@std/bytes@^1.0.2": "1.0.4", "jsr:@std/bytes@^1.0.2": "1.0.4",
"jsr:@std/cli@*": "1.0.6",
"jsr:@std/crypto@1": "1.0.3", "jsr:@std/crypto@1": "1.0.3",
"jsr:@std/encoding@1": "1.0.5", "jsr:@std/encoding@1": "1.0.5",
"jsr:@std/encoding@^1.0.5": "1.0.5", "jsr:@std/encoding@^1.0.5": "1.0.5",
@ -48,6 +49,9 @@
"@std/bytes@1.0.4": { "@std/bytes@1.0.4": {
"integrity": "11a0debe522707c95c7b7ef89b478c13fb1583a7cfb9a85674cd2cc2e3a28abc" "integrity": "11a0debe522707c95c7b7ef89b478c13fb1583a7cfb9a85674cd2cc2e3a28abc"
}, },
"@std/cli@1.0.6": {
"integrity": "d22d8b38c66c666d7ad1f2a66c5b122da1704f985d3c47f01129f05abb6c5d3d"
},
"@std/crypto@1.0.3": { "@std/crypto@1.0.3": {
"integrity": "a2a32f51ddef632d299e3879cd027c630dcd4d1d9a5285d6e6788072f4e51e7f" "integrity": "a2a32f51ddef632d299e3879cd027c630dcd4d1d9a5285d6e6788072f4e51e7f"
}, },

View File

@ -1,13 +1,110 @@
import { Application, Router } from "jsr:@oak/oak"; import { Application, Router } from "jsr:@oak/oak";
import { parseArgs } from "jsr:@std/cli/parse-args";
import { Runtime } from "./runtime.ts";
import * as compiler from "../compiler/mod.ts";
const port = 8000;
const app = new Application(); const flags = parseArgs(Deno.args, {
boolean: ["flame-graph", "code-coverage"],
});
if (flags._.length !== 1) {
throw new Error("please specify a filename");
}
const filepath = flags._[0] as string;
const text = await Deno.readTextFile(filepath);
const runtime = new Runtime(13370);
async function compileProgram(filepath: string) {
const result = await compiler.compileWithDebug(filepath);
}
async function runProgramWithDebug(program: string) {
const connection = await runtime.connect();
connection.send({
type: "run-debug",
program,
});
const res = await connection.receive<{
ok: boolean;
}>();
connection.close();
if (!res.ok) {
throw new Error("could not run code");
}
}
const router = new Router(); const router = new Router();
router.get("/api/source", (ctx) => {
ctx.response.body = { ok: true, filepath, text };
ctx.response.status = 200;
ctx.respond = true;
});
router.get("/api/status", async (ctx) => {
const connection = await runtime.connect();
connection.send({ type: "status" });
const res = await connection.receive<{
ok: boolean;
status: "running" | "done";
}>();
connection.close();
if (!res.ok) {
ctx.response.body = { ok: false };
ctx.response.status = 500;
ctx.respond = true;
return;
}
ctx.response.body = { ok: true, status: res.status };
ctx.response.status = 200;
ctx.respond = true;
});
router.get("/api/flame-graph", async (ctx) => {
const connection = await runtime.connect();
connection.send({ type: "flame-graph" });
const res = await connection.receive<{
ok: boolean;
flameGraph: string;
}>();
connection.close();
if (!res.ok) {
ctx.response.body = { ok: false };
ctx.response.status = 500;
ctx.respond = true;
return;
}
ctx.response.body = { ok: true, flameGraph: res.flameGraph };
ctx.response.status = 200;
ctx.respond = true;
});
router.get("/api/code-coverage", async (ctx) => {
const connection = await runtime.connect();
connection.send({ type: "code-coverage" });
const res = await connection.receive<{
ok: boolean;
codeCoverage: string;
}>();
connection.close();
if (!res.ok) {
ctx.response.body = { ok: false };
ctx.response.status = 500;
ctx.respond = true;
return;
}
ctx.response.body = { ok: true, codeCoverage: res.codeCoverage };
ctx.response.status = 200;
ctx.respond = true;
});
const app = new Application();
app.use(router.routes()); app.use(router.routes());
app.use(router.allowedMethods()); app.use(router.allowedMethods());
app.use(async (ctx, next) => { app.use(async (ctx, next) => {
try { try {
await ctx.send({ root: "./public", index: "index.html" }); await ctx.send({ root: "./public", index: "index.html" });
@ -15,8 +112,6 @@ app.use(async (ctx, next) => {
next(); next();
} }
}); });
const port = 8000;
const listener = app.listen({ port }); const listener = app.listen({ port });
console.log(`Listening at http://localhost:${port}/`); console.log(`Devtools at http://localhost:${port}/`);
await listener; await listener;

View File

@ -30,6 +30,11 @@ function loadCodeCoverage(text, codeCoverageData) {
let line = 1; let line = 1;
let col = 1; let col = 1;
for (let index = 0; index < text.length; ++index) { for (let index = 0; index < text.length; ++index) {
if (text[index] == "\n") {
col = 1;
line += 1;
continue;
}
const entry = entries.find((entry) => index >= entry.index); const entry = entries.find((entry) => index >= entry.index);
charEntries[`${line}-${col}`] = entry; charEntries[`${line}-${col}`] = entry;
ctx.fillStyle = color(Math.min(entry.covers / 25, 1)); ctx.fillStyle = color(Math.min(entry.covers / 25, 1));
@ -40,10 +45,6 @@ function loadCodeCoverage(text, codeCoverageData) {
chHeight, chHeight,
); );
col += 1; col += 1;
if (text[index] == "\n") {
col = 1;
line += 1;
}
} }
const tooltip = document.getElementById("covers-tooltip"); const tooltip = document.getElementById("covers-tooltip");

View File

@ -50,7 +50,7 @@ main {
} }
#code-coverage #covers-tooltip { #code-coverage #covers-tooltip {
z-index: 2; z-index: 2;
position: absolute; position: fixed;
top: 0; top: 0;
left: 0; left: 0;
padding: 3px; padding: 3px;
@ -78,7 +78,7 @@ main {
} }
#flame-graph #flame-graph-tooltip { #flame-graph #flame-graph-tooltip {
z-index: 2; z-index: 2;
position: absolute; position: fixed;
top: 0; top: 0;
left: 0; left: 0;
padding: 3px; padding: 3px;

45
web/runtime.ts Normal file
View File

@ -0,0 +1,45 @@
export class Runtime {
constructor(private port: number) {}
async connect(): Promise<RuntimeConnection> {
return new RuntimeConnection(
await Deno.connect({
port: this.port,
}),
);
}
}
export class RuntimeConnection {
constructor(private connection: Deno.Conn) {}
async write(text: string): Promise<void> {
const req = new TextEncoder().encode(text);
await this.connection.write(req);
}
async send<T>(value: T): Promise<void> {
await this.write(JSON.stringify(value));
}
async read(): Promise<string> {
let result = "";
while (true) {
const buf = new Uint8Array(256);
const readRes = await this.connection.read(buf);
result += new TextDecoder().decode(buf);
if (readRes == null) {
break;
}
}
return result;
}
async receive<T>(): Promise<T> {
return JSON.parse(await this.read()) as T;
}
close() {
this.connection.close();
}
}