mirror of
https://git.sfja.dk/Mikkel/slige.git
synced 2025-01-18 19:36:32 +00:00
web, runtime, compiler, connections
This commit is contained in:
parent
7806b64783
commit
af8ce1d47a
14
compiler/mod.ts
Normal file
14
compiler/mod.ts
Normal 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();
|
||||||
|
}
|
@ -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"
|
||||||
},
|
},
|
||||||
|
105
web/main.ts
105
web/main.ts
@ -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;
|
||||||
|
@ -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");
|
||||||
|
@ -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
45
web/runtime.ts
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user