mirror of
https://git.sfja.dk/Mikkel/slige.git
synced 2025-01-18 09:46:30 +00:00
fix labels, return, code coverage
This commit is contained in:
parent
b2bdf471f0
commit
77c01e12a5
@ -22,6 +22,8 @@ export const Ops = {
|
|||||||
Jump: 0x0e,
|
Jump: 0x0e,
|
||||||
JumpIfTrue: 0x0f,
|
JumpIfTrue: 0x0f,
|
||||||
Builtin: 0x10,
|
Builtin: 0x10,
|
||||||
|
Duplicate: 0x11,
|
||||||
|
Swap: 0x12,
|
||||||
Add: 0x20,
|
Add: 0x20,
|
||||||
Subtract: 0x21,
|
Subtract: 0x21,
|
||||||
Multiply: 0x22,
|
Multiply: 0x22,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Ops, opToString } from "./arch.ts";
|
import { opToString } from "./arch.ts";
|
||||||
|
|
||||||
export type Line = { labels?: string[]; ins: Ins };
|
export type Line = { labels?: string[]; ins: Ins };
|
||||||
|
|
||||||
@ -14,7 +14,28 @@ export type Refs = { [key: number]: string };
|
|||||||
export class Assembler {
|
export class Assembler {
|
||||||
private lines: Line[] = [];
|
private lines: Line[] = [];
|
||||||
private addedLabels: string[] = [];
|
private addedLabels: string[] = [];
|
||||||
private labelCounter = 0;
|
|
||||||
|
private constructor(private labelCounter: number) {}
|
||||||
|
|
||||||
|
public static newRoot(): Assembler {
|
||||||
|
return new Assembler(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public fork(): Assembler {
|
||||||
|
return new Assembler(this.labelCounter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public join(assembler: Assembler) {
|
||||||
|
this.labelCounter = assembler.labelCounter;
|
||||||
|
if (assembler.lines.length < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (assembler.lines[0].labels !== undefined) {
|
||||||
|
this.addedLabels.push(...assembler.lines[0].labels);
|
||||||
|
}
|
||||||
|
this.add(...assembler.lines[0].ins);
|
||||||
|
this.lines.push(...assembler.lines.slice(1));
|
||||||
|
}
|
||||||
|
|
||||||
public add(...ins: Ins): Assembler {
|
public add(...ins: Ins): Assembler {
|
||||||
if (this.addedLabels.length > 0) {
|
if (this.addedLabels.length > 0) {
|
||||||
@ -26,17 +47,6 @@ export class Assembler {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public concat(assembler: Assembler) {
|
|
||||||
if (assembler.lines.length < 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (assembler.lines[0].labels !== undefined) {
|
|
||||||
this.addedLabels.push(...assembler.lines[0].labels);
|
|
||||||
}
|
|
||||||
this.add(...assembler.lines[0].ins);
|
|
||||||
this.lines.push(...assembler.lines.slice(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
public makeLabel(): Label {
|
public makeLabel(): Label {
|
||||||
return { label: `.L${(this.labelCounter++).toString()}` };
|
return { label: `.L${(this.labelCounter++).toString()}` };
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ import { Pos } from "./token.ts";
|
|||||||
export type FnNamesMap = { [pc: number]: string };
|
export type FnNamesMap = { [pc: number]: string };
|
||||||
|
|
||||||
export class Lowerer {
|
export class Lowerer {
|
||||||
private program = new Assembler();
|
private program = Assembler.newRoot();
|
||||||
private locals: Locals = new LocalsFnRoot();
|
private locals: Locals = new LocalsFnRoot();
|
||||||
private fnStmtIdLabelMap: { [stmtId: number]: string } = {};
|
private fnStmtIdLabelMap: { [stmtId: number]: string } = {};
|
||||||
private fnLabelNameMap: { [name: string]: string } = {};
|
private fnLabelNameMap: { [name: string]: string } = {};
|
||||||
@ -19,16 +19,16 @@ export class Lowerer {
|
|||||||
|
|
||||||
public lower(stmts: Stmt[]) {
|
public lower(stmts: Stmt[]) {
|
||||||
this.addClearingSourceMap();
|
this.addClearingSourceMap();
|
||||||
this.program.add(Ops.PushPtr, { label: "_start" });
|
this.program.add(Ops.PushPtr, { label: "main" });
|
||||||
|
this.program.add(Ops.Call, 0);
|
||||||
|
this.program.add(Ops.PushPtr, { label: "_exit" });
|
||||||
this.program.add(Ops.Jump);
|
this.program.add(Ops.Jump);
|
||||||
this.scoutFnHeaders(stmts);
|
this.scoutFnHeaders(stmts);
|
||||||
for (const stmt of stmts) {
|
for (const stmt of stmts) {
|
||||||
this.lowerStaticStmt(stmt);
|
this.lowerStaticStmt(stmt);
|
||||||
}
|
}
|
||||||
this.program.setLabel({ label: "_start" });
|
this.program.setLabel({ label: "_exit" });
|
||||||
this.addSourceMap(this.lastPos);
|
this.addSourceMap(this.lastPos);
|
||||||
this.program.add(Ops.PushPtr, { label: "main" });
|
|
||||||
this.program.add(Ops.Call, 0);
|
|
||||||
this.program.add(Ops.Pop);
|
this.program.add(Ops.Pop);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,7 +171,7 @@ export class Lowerer {
|
|||||||
const returnLabel = this.program.makeLabel();
|
const returnLabel = this.program.makeLabel();
|
||||||
this.returnStack.push(returnLabel);
|
this.returnStack.push(returnLabel);
|
||||||
|
|
||||||
this.program = new Assembler();
|
this.program = outerProgram.fork();
|
||||||
this.locals = fnRoot;
|
this.locals = fnRoot;
|
||||||
for (const { ident } of stmt.kind.params) {
|
for (const { ident } of stmt.kind.params) {
|
||||||
this.locals.allocSym(ident);
|
this.locals.allocSym(ident);
|
||||||
@ -185,18 +185,17 @@ export class Lowerer {
|
|||||||
}
|
}
|
||||||
this.locals = outerLocals;
|
this.locals = outerLocals;
|
||||||
|
|
||||||
this.returnStack.pop();
|
|
||||||
this.program.setLabel(returnLabel);
|
|
||||||
|
|
||||||
const localAmount = fnRoot.stackReserved() -
|
const localAmount = fnRoot.stackReserved() -
|
||||||
stmt.kind.params.length;
|
stmt.kind.params.length;
|
||||||
for (let i = 0; i < localAmount; ++i) {
|
for (let i = 0; i < localAmount; ++i) {
|
||||||
outerProgram.add(Ops.PushNull);
|
outerProgram.add(Ops.PushNull);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.returnStack.pop();
|
||||||
|
this.program.setLabel(returnLabel);
|
||||||
this.program.add(Ops.Return);
|
this.program.add(Ops.Return);
|
||||||
|
|
||||||
outerProgram.concat(this.program);
|
outerProgram.join(this.program);
|
||||||
this.program = outerProgram;
|
this.program = outerProgram;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -353,9 +352,8 @@ export class Lowerer {
|
|||||||
switch (expr.kind.unaryType) {
|
switch (expr.kind.unaryType) {
|
||||||
case "-": {
|
case "-": {
|
||||||
this.program.add(Ops.PushInt, 0);
|
this.program.add(Ops.PushInt, 0);
|
||||||
this.program.add(Ops.PushInt, 1);
|
this.program.add(Ops.Swap);
|
||||||
this.program.add(Ops.Subtract);
|
this.program.add(Ops.Subtract);
|
||||||
this.program.add(Ops.Multiply);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -373,9 +371,25 @@ export class Lowerer {
|
|||||||
if (expr.kind.type !== "binary") {
|
if (expr.kind.type !== "binary") {
|
||||||
throw new Error();
|
throw new Error();
|
||||||
}
|
}
|
||||||
|
const vtype = expr.kind.left.vtype!;
|
||||||
|
if (vtype.type === "bool") {
|
||||||
|
if (["or", "and"].includes(expr.kind.binaryType)) {
|
||||||
|
const shortCircuitLabel = this.program.makeLabel();
|
||||||
|
this.lowerExpr(expr.kind.left);
|
||||||
|
this.program.add(Ops.Duplicate);
|
||||||
|
if (expr.kind.binaryType === "and") {
|
||||||
|
this.program.add(Ops.Not);
|
||||||
|
}
|
||||||
|
this.program.add(Ops.PushPtr, shortCircuitLabel);
|
||||||
|
this.program.add(Ops.JumpIfTrue);
|
||||||
|
this.program.add(Ops.Pop);
|
||||||
|
this.lowerExpr(expr.kind.right);
|
||||||
|
this.program.setLabel(shortCircuitLabel);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
this.lowerExpr(expr.kind.left);
|
this.lowerExpr(expr.kind.left);
|
||||||
this.lowerExpr(expr.kind.right);
|
this.lowerExpr(expr.kind.right);
|
||||||
const vtype = expr.kind.left.vtype!;
|
|
||||||
if (vtype.type === "int") {
|
if (vtype.type === "int") {
|
||||||
switch (expr.kind.binaryType) {
|
switch (expr.kind.binaryType) {
|
||||||
case "+":
|
case "+":
|
||||||
@ -387,6 +401,9 @@ export class Lowerer {
|
|||||||
case "*":
|
case "*":
|
||||||
this.program.add(Ops.Multiply);
|
this.program.add(Ops.Multiply);
|
||||||
return;
|
return;
|
||||||
|
case "/":
|
||||||
|
this.program.add(Ops.Multiply);
|
||||||
|
return;
|
||||||
case "==":
|
case "==":
|
||||||
this.program.add(Ops.Equal);
|
this.program.add(Ops.Equal);
|
||||||
return;
|
return;
|
||||||
@ -397,6 +414,15 @@ export class Lowerer {
|
|||||||
case "<":
|
case "<":
|
||||||
this.program.add(Ops.LessThan);
|
this.program.add(Ops.LessThan);
|
||||||
return;
|
return;
|
||||||
|
case ">":
|
||||||
|
this.program.add(Ops.Swap);
|
||||||
|
this.program.add(Ops.LessThan);
|
||||||
|
return;
|
||||||
|
case "<=":
|
||||||
|
this.program.add(Ops.Swap);
|
||||||
|
this.program.add(Ops.LessThan);
|
||||||
|
this.program.add(Ops.Not);
|
||||||
|
return;
|
||||||
case ">=":
|
case ">=":
|
||||||
this.program.add(Ops.LessThan);
|
this.program.add(Ops.LessThan);
|
||||||
this.program.add(Ops.Not);
|
this.program.add(Ops.Not);
|
||||||
@ -419,16 +445,6 @@ export class Lowerer {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (vtype.type === "bool") {
|
|
||||||
if (expr.kind.binaryType === "or") {
|
|
||||||
this.program.add(Ops.Or);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (expr.kind.binaryType === "and") {
|
|
||||||
this.program.add(Ops.And);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`unhandled binaryType` +
|
`unhandled binaryType` +
|
||||||
` '${vtypeToString(expr.vtype!)}' aka. ` +
|
` '${vtypeToString(expr.vtype!)}' aka. ` +
|
||||||
|
@ -7,10 +7,8 @@ fn string_to_int_impl(text: string) -> int {
|
|||||||
|
|
||||||
let len = string_length(text);
|
let len = string_length(text);
|
||||||
if len == 0 {
|
if len == 0 {
|
||||||
return 1;
|
return -1;
|
||||||
}
|
}
|
||||||
println("hello world");
|
|
||||||
|
|
||||||
if text[0] == "0"[0] {
|
if text[0] == "0"[0] {
|
||||||
if len == 1 {
|
if len == 1 {
|
||||||
0
|
0
|
||||||
@ -41,27 +39,28 @@ fn parse_digits(text: string, base: int, digit_set: string) -> int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn char_val(ch: int) -> int {
|
fn char_val(ch: int) -> int {
|
||||||
if ch >= "0"[0] and "9"[0] >= ch {
|
if ch >= "0"[0] and ch <= "9"[0] {
|
||||||
ch - "0"[0]
|
ch - "0"[0]
|
||||||
} else if ch >= "a"[0] and "f"[0] >= ch {
|
} else if ch >= "a"[0] and ch <= "f"[0] {
|
||||||
ch - "a"[0]
|
ch - "a"[0] + 10
|
||||||
} else {
|
} else {
|
||||||
-1
|
-1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_string_to_int_impl() -> bool {
|
fn test_string_to_int_impl() -> bool {
|
||||||
test("should convert zero", assert_int_equal(string_to_int_impl("0"), 0))
|
test("should convert zero", assert_int_equal(string_to_int_impl("0"), 0))
|
||||||
or test("should convert decimal", assert_int_equal(string_to_int_impl("10"), 10))
|
and test("should convert decimal", assert_int_equal(string_to_int_impl("10"), 10))
|
||||||
or test("should convert binary", assert_int_equal(string_to_int_impl("0b110"), 6))
|
and test("should convert binary", assert_int_equal(string_to_int_impl("0b110"), 6))
|
||||||
or test("should convert octal", assert_int_equal(string_to_int_impl("071"), 51))
|
and test("should convert octal", assert_int_equal(string_to_int_impl("071"), 57))
|
||||||
or test("should convert hexadecimal", assert_int_equal(string_to_int_impl("0xaa"), 170))
|
and test("should convert hex", assert_int_equal(string_to_int_impl("0xaa"), 170))
|
||||||
or test("should fail", assert_int_equal(string_to_int_impl("john"), -1))
|
and test("should fail", assert_int_equal(string_to_int_impl("john"), -1))
|
||||||
|
and test("should fail", assert_int_equal(string_to_int_impl(""), -1))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assert_int_equal(value: int, target: int) -> bool {
|
fn assert_int_equal(value: int, target: int) -> bool {
|
||||||
if value != target {
|
if value != target {
|
||||||
println("assertion failed: " + int_to_string(value) + " != " + int_to_string(target));
|
println("assertion failed: " + itos(value) + " != " + itos(target));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
true
|
true
|
||||||
@ -109,6 +108,8 @@ fn file_read_to_string(file: int) -> string #[builtin(FileReadToString)] {}
|
|||||||
fn file_flush(file: int) #[builtin(FileFlush)] {}
|
fn file_flush(file: int) #[builtin(FileFlush)] {}
|
||||||
fn file_eof(file: int) -> bool #[builtin(FileEof)] {}
|
fn file_eof(file: int) -> bool #[builtin(FileEof)] {}
|
||||||
|
|
||||||
|
fn itos(number: int) -> string #[builtin(IntToString)] {}
|
||||||
|
fn stoi(str: string) -> int #[builtin(StringToInt)] {}
|
||||||
|
|
||||||
fn stdin() -> int { 0 }
|
fn stdin() -> int { 0 }
|
||||||
fn stdout() -> int { 1 }
|
fn stdout() -> int { 1 }
|
||||||
@ -175,11 +176,11 @@ fn string_split(str: string, seperator: int) -> [string] {
|
|||||||
fn string_slice(str: string, from: int, to: int) -> string {
|
fn string_slice(str: string, from: int, to: int) -> string {
|
||||||
let result = "";
|
let result = "";
|
||||||
let len = string_length(str);
|
let len = string_length(str);
|
||||||
let actual_to =
|
let abs_to =
|
||||||
if to >= len { len }
|
if to >= len { len }
|
||||||
else if to < 0 { len - to }
|
else if to < 0 { len + to + 1 }
|
||||||
else { to };
|
else { to };
|
||||||
for (let i = from; i < actual_to; i += i) {
|
for (let i = from; i < abs_to; i += 1) {
|
||||||
result = string_push_char(result, str[i]);
|
result = string_push_char(result, str[i]);
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
|
@ -24,6 +24,8 @@ enum class Op : uint32_t {
|
|||||||
Jump = 0x0e,
|
Jump = 0x0e,
|
||||||
JumpIfTrue = 0x0f,
|
JumpIfTrue = 0x0f,
|
||||||
Builtin = 0x10,
|
Builtin = 0x10,
|
||||||
|
Duplicate = 0x11,
|
||||||
|
Swap = 0x12,
|
||||||
Add = 0x20,
|
Add = 0x20,
|
||||||
Subtract = 0x21,
|
Subtract = 0x21,
|
||||||
Multiply = 0x22,
|
Multiply = 0x22,
|
||||||
|
@ -33,6 +33,8 @@ size_t VM::instruction_size(size_t i) const
|
|||||||
return 1;
|
return 1;
|
||||||
case Op::Builtin:
|
case Op::Builtin:
|
||||||
return 2;
|
return 2;
|
||||||
|
case Op::Duplicate:
|
||||||
|
case Op::Swap:
|
||||||
case Op::Add:
|
case Op::Add:
|
||||||
case Op::Subtract:
|
case Op::Subtract:
|
||||||
case Op::Multiply:
|
case Op::Multiply:
|
||||||
|
@ -25,6 +25,8 @@ auto sliger::maybe_op_to_string(uint32_t value) -> std::string
|
|||||||
case Op::Jump: return "Jump";
|
case Op::Jump: return "Jump";
|
||||||
case Op::JumpIfTrue: return "JumpIfTrue";
|
case Op::JumpIfTrue: return "JumpIfTrue";
|
||||||
case Op::Builtin: return "Builtin";
|
case Op::Builtin: return "Builtin";
|
||||||
|
case Op::Duplicate: return "Duplicate";
|
||||||
|
case Op::Swap: return "Swap";
|
||||||
case Op::Add: return "Add";
|
case Op::Add: return "Add";
|
||||||
case Op::Subtract: return "Subtract";
|
case Op::Subtract: return "Subtract";
|
||||||
case Op::Multiply: return "Multiply";
|
case Op::Multiply: return "Multiply";
|
||||||
@ -37,10 +39,9 @@ auto sliger::maybe_op_to_string(uint32_t value) -> std::string
|
|||||||
case Op::Xor: return "Xor";
|
case Op::Xor: return "Xor";
|
||||||
case Op::Not: return "Not";
|
case Op::Not: return "Not";
|
||||||
case Op::SourceMap: return "SourceMap";
|
case Op::SourceMap: return "SourceMap";
|
||||||
/* clang-format on */
|
/* clang-format on */
|
||||||
default:
|
|
||||||
return std::to_string(value);
|
|
||||||
}
|
}
|
||||||
|
return std::to_string(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto sliger::maybe_builtin_to_string(uint32_t value) -> std::string
|
auto sliger::maybe_builtin_to_string(uint32_t value) -> std::string
|
||||||
|
@ -177,6 +177,21 @@ void VM::run_instruction()
|
|||||||
run_builtin(static_cast<Builtin>(builtin_id));
|
run_builtin(static_cast<Builtin>(builtin_id));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case Op::Duplicate: {
|
||||||
|
assert_stack_has(1);
|
||||||
|
auto value = stack_pop();
|
||||||
|
stack_push(value);
|
||||||
|
stack_push(value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op::Swap: {
|
||||||
|
assert_stack_has(2);
|
||||||
|
auto right = stack_pop();
|
||||||
|
auto left = stack_pop();
|
||||||
|
stack_push(right);
|
||||||
|
stack_push(left);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case Op::Add: {
|
case Op::Add: {
|
||||||
assert_stack_has(2);
|
assert_stack_has(2);
|
||||||
auto right = stack_pop().as_int().value;
|
auto right = stack_pop().as_int().value;
|
||||||
|
@ -27,6 +27,8 @@ fn file_read_to_string(file: int) -> string #[builtin(FileReadToString)] {}
|
|||||||
fn file_flush(file: int) #[builtin(FileFlush)] {}
|
fn file_flush(file: int) #[builtin(FileFlush)] {}
|
||||||
fn file_eof(file: int) -> bool #[builtin(FileEof)] {}
|
fn file_eof(file: int) -> bool #[builtin(FileEof)] {}
|
||||||
|
|
||||||
|
fn itos(number: int) -> string #[builtin(IntToString)] {}
|
||||||
|
fn stoi(str: string) -> int #[builtin(StringToInt)] {}
|
||||||
|
|
||||||
fn stdin() -> int { 0 }
|
fn stdin() -> int { 0 }
|
||||||
fn stdout() -> int { 1 }
|
fn stdout() -> int { 1 }
|
||||||
|
@ -2,6 +2,11 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,100..700;1,100..700&display=swap" rel="stylesheet">
|
||||||
|
|
||||||
<link rel="stylesheet" href="style.css">
|
<link rel="stylesheet" href="style.css">
|
||||||
<script src="dist/bundle.js" type="module" defer></script>
|
<script src="dist/bundle.js" type="module" defer></script>
|
||||||
</head>
|
</head>
|
||||||
|
@ -27,7 +27,7 @@ export function loadFlameGraph(
|
|||||||
canvas.width = 1000;
|
canvas.width = 1000;
|
||||||
canvas.height = 500;
|
canvas.height = 500;
|
||||||
|
|
||||||
const fnNameFont = "600 14px monospace";
|
const fnNameFont = "600 14px 'Roboto Mono'";
|
||||||
|
|
||||||
const ctx = canvas.getContext("2d")!;
|
const ctx = canvas.getContext("2d")!;
|
||||||
ctx.font = fnNameFont;
|
ctx.font = fnNameFont;
|
||||||
@ -39,7 +39,7 @@ export function loadFlameGraph(
|
|||||||
h: number;
|
h: number;
|
||||||
title: string;
|
title: string;
|
||||||
percent: string;
|
percent: string;
|
||||||
fgNode: FlameGraphNode;
|
fgNode: data.FlameGraphNode;
|
||||||
};
|
};
|
||||||
|
|
||||||
function calculateNodeRects(
|
function calculateNodeRects(
|
||||||
@ -91,14 +91,40 @@ export function loadFlameGraph(
|
|||||||
for (const node of nodes) {
|
for (const node of nodes) {
|
||||||
const { x, y, w, h } = node;
|
const { x, y, w, h } = node;
|
||||||
ctx.fillStyle = "rgb(255, 125, 0)";
|
ctx.fillStyle = "rgb(255, 125, 0)";
|
||||||
ctx.fillRect(
|
ctx.fillRect(x + 2, y + 2, w - 4, h - 4);
|
||||||
x + 2,
|
|
||||||
y + 2,
|
|
||||||
w - 4,
|
|
||||||
h - 4,
|
|
||||||
);
|
|
||||||
const textCanvas = drawTextCanvas(node);
|
const textCanvas = drawTextCanvas(node);
|
||||||
ctx.drawImage(textCanvas, x + 4, y);
|
ctx.drawImage(textCanvas, x + 4, y);
|
||||||
|
|
||||||
|
const edgePadding = 4;
|
||||||
|
const edgeWidth = 8;
|
||||||
|
|
||||||
|
const leftGradient = ctx.createLinearGradient(
|
||||||
|
x + 2 + edgePadding,
|
||||||
|
0,
|
||||||
|
x + 2 + edgeWidth,
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
leftGradient.addColorStop(1, "rgba(255, 125, 0, 0.0)");
|
||||||
|
leftGradient.addColorStop(0, "rgba(255, 125, 0, 1.0)");
|
||||||
|
ctx.fillStyle = leftGradient;
|
||||||
|
ctx.fillRect(x + 2, y + 2, Math.min(edgeWidth, (w - 4) / 2), h - 4);
|
||||||
|
|
||||||
|
const rightGradient = ctx.createLinearGradient(
|
||||||
|
x + w - 2 - edgeWidth,
|
||||||
|
0,
|
||||||
|
x + w - 2 - edgePadding,
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
rightGradient.addColorStop(0, "rgba(255, 125, 0, 0.0)");
|
||||||
|
rightGradient.addColorStop(1, "rgba(255, 125, 0, 1.0)");
|
||||||
|
ctx.fillStyle = rightGradient;
|
||||||
|
ctx.fillRect(
|
||||||
|
x + w - 2 - Math.min(edgeWidth, (w - 4) / 2),
|
||||||
|
y + 2,
|
||||||
|
Math.min(edgeWidth, (w - 4) / 2),
|
||||||
|
h - 4,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
const tooltip = document.getElementById("flame-graph-tooltip")!;
|
const tooltip = document.getElementById("flame-graph-tooltip")!;
|
||||||
|
|
||||||
|
@ -104,6 +104,11 @@ main #cover {
|
|||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#view .code-container pre {
|
||||||
|
font-family: "Roboto Mono", monospace;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
#view .code-container.code-coverage {
|
#view .code-container.code-coverage {
|
||||||
max-height: calc(100% - 103px);
|
max-height: calc(100% - 103px);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user