Compare commits
	
		
			2 Commits
		
	
	
		
			b2bdf471f0
			...
			fee5666971
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| fee5666971 | |||
| 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,10 +39,10 @@ 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
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -52,16 +50,17 @@ fn char_val(ch: int) -> int {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
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";
 | 
				
			||||||
@ -38,9 +40,8 @@ auto sliger::maybe_op_to_string(uint32_t value) -> std::string
 | 
				
			|||||||
        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")!;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -40,6 +40,200 @@ async function checkStatus(): Promise<"running" | "done"> {
 | 
				
			|||||||
    return "done";
 | 
					    return "done";
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function syntaxHighlight(code: string): string {
 | 
				
			||||||
 | 
					    const colors = {
 | 
				
			||||||
 | 
					        colorBackground: "#282828",
 | 
				
			||||||
 | 
					        colorForeground: "#fbf1c7",
 | 
				
			||||||
 | 
					        colorKeyword: "#fb4934",
 | 
				
			||||||
 | 
					        colorIdentifier: "#83a598",
 | 
				
			||||||
 | 
					        colorOperator: "#fe8019",
 | 
				
			||||||
 | 
					        colorSpecial: "#fe8019",
 | 
				
			||||||
 | 
					        colorType: "#fabd2f",
 | 
				
			||||||
 | 
					        colorBoolean: "#d3869b",
 | 
				
			||||||
 | 
					        colorNumber: "#d3869b",
 | 
				
			||||||
 | 
					        colorString: "#b8bb26",
 | 
				
			||||||
 | 
					        colorComment: "#928374",
 | 
				
			||||||
 | 
					        colorFunction: "#b8bb26",
 | 
				
			||||||
 | 
					        colorLineNumber: "#7c6f64",
 | 
				
			||||||
 | 
					    } as const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					    Keyword = { link = "GruvboxRed" },
 | 
				
			||||||
 | 
					    Identifier = { link = "GruvboxBlue" },
 | 
				
			||||||
 | 
					    Operator = { fg = colors.orange, italic = config.italic.operators },
 | 
				
			||||||
 | 
					    Special = { link = "GruvboxOrange" },
 | 
				
			||||||
 | 
					    Type = { link = "GruvboxYellow" },
 | 
				
			||||||
 | 
					    Boolean = { link = "GruvboxPurple" },
 | 
				
			||||||
 | 
					    Number = { link = "GruvboxPurple" },
 | 
				
			||||||
 | 
					    String = { fg = colors.green, italic = config.italic.strings },
 | 
				
			||||||
 | 
					    Comment = { fg = colors.gray, italic = config.italic.comments },
 | 
				
			||||||
 | 
					    Function = { link = "GruvboxGreenBold" },
 | 
				
			||||||
 | 
					    */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let matches: {
 | 
				
			||||||
 | 
					        index: number;
 | 
				
			||||||
 | 
					        length: number;
 | 
				
			||||||
 | 
					        color: string;
 | 
				
			||||||
 | 
					        extra: string;
 | 
				
			||||||
 | 
					    }[] = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    function addMatches(color: string, re: RegExp, extra = "") {
 | 
				
			||||||
 | 
					        for (const match of code.matchAll(re)) {
 | 
				
			||||||
 | 
					            matches.push({
 | 
				
			||||||
 | 
					                index: match.index,
 | 
				
			||||||
 | 
					                length: match[1].length,
 | 
				
			||||||
 | 
					                color,
 | 
				
			||||||
 | 
					                extra,
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    function addKeywordMatches(color: string, keywords: string[]) {
 | 
				
			||||||
 | 
					        addMatches(
 | 
				
			||||||
 | 
					            color,
 | 
				
			||||||
 | 
					            new RegExp(
 | 
				
			||||||
 | 
					                `(?<!\\w)(${
 | 
				
			||||||
 | 
					                    keywords.map((kw) => `(?:${kw})`).join("|")
 | 
				
			||||||
 | 
					                })(?!\\w)`,
 | 
				
			||||||
 | 
					                "g",
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (let i = 0; i < code.length; ++i) {
 | 
				
			||||||
 | 
					        if (code[i] !== '"') {
 | 
				
			||||||
 | 
					            continue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        let last = code[i];
 | 
				
			||||||
 | 
					        const index = i;
 | 
				
			||||||
 | 
					        i += 1;
 | 
				
			||||||
 | 
					        while (i < code.length && !(code[i] === '"' && last !== "\\")) {
 | 
				
			||||||
 | 
					            last = code[i];
 | 
				
			||||||
 | 
					            i += 1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (i < code.length) {
 | 
				
			||||||
 | 
					            i += 1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        matches.push({
 | 
				
			||||||
 | 
					            index,
 | 
				
			||||||
 | 
					            length: i - index,
 | 
				
			||||||
 | 
					            color: colors.colorString,
 | 
				
			||||||
 | 
					            extra: "font-style: italic;",
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        let last = "";
 | 
				
			||||||
 | 
					        for (let i = 0; i < code.length; ++i) {
 | 
				
			||||||
 | 
					            if (last === "/" && code[i] === "/") {
 | 
				
			||||||
 | 
					                const index = i - 1;
 | 
				
			||||||
 | 
					                while (i < code.length && code[i] !== "\n") {
 | 
				
			||||||
 | 
					                    i += 1;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                matches.push({
 | 
				
			||||||
 | 
					                    index,
 | 
				
			||||||
 | 
					                    length: i - index,
 | 
				
			||||||
 | 
					                    color: colors.colorComment,
 | 
				
			||||||
 | 
					                    extra: "font-style: italic;",
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            last = code[i];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    addKeywordMatches(
 | 
				
			||||||
 | 
					        colors.colorKeyword,
 | 
				
			||||||
 | 
					        [
 | 
				
			||||||
 | 
					            "break",
 | 
				
			||||||
 | 
					            "return",
 | 
				
			||||||
 | 
					            "let",
 | 
				
			||||||
 | 
					            "fn",
 | 
				
			||||||
 | 
					            "if",
 | 
				
			||||||
 | 
					            "else",
 | 
				
			||||||
 | 
					            "struct",
 | 
				
			||||||
 | 
					            "import",
 | 
				
			||||||
 | 
					            "or",
 | 
				
			||||||
 | 
					            "and",
 | 
				
			||||||
 | 
					            "not",
 | 
				
			||||||
 | 
					            "while",
 | 
				
			||||||
 | 
					            "for",
 | 
				
			||||||
 | 
					            "in",
 | 
				
			||||||
 | 
					        ],
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    addKeywordMatches(colors.colorSpecial, ["null"]);
 | 
				
			||||||
 | 
					    addKeywordMatches(colors.colorType, ["int", "string", "bool"]);
 | 
				
			||||||
 | 
					    addKeywordMatches(colors.colorBoolean, ["false", "true"]);
 | 
				
			||||||
 | 
					    addMatches(
 | 
				
			||||||
 | 
					        colors.colorOperator,
 | 
				
			||||||
 | 
					        new RegExp(
 | 
				
			||||||
 | 
					            `(${
 | 
				
			||||||
 | 
					                [
 | 
				
			||||||
 | 
					                    "\\+=",
 | 
				
			||||||
 | 
					                    "\\-=",
 | 
				
			||||||
 | 
					                    "\\+",
 | 
				
			||||||
 | 
					                    "\\->",
 | 
				
			||||||
 | 
					                    "\\-",
 | 
				
			||||||
 | 
					                    "\\*",
 | 
				
			||||||
 | 
					                    "/",
 | 
				
			||||||
 | 
					                    "==",
 | 
				
			||||||
 | 
					                    "!=",
 | 
				
			||||||
 | 
					                    "<=",
 | 
				
			||||||
 | 
					                    ">=",
 | 
				
			||||||
 | 
					                    "=",
 | 
				
			||||||
 | 
					                    "<",
 | 
				
			||||||
 | 
					                    ">",
 | 
				
			||||||
 | 
					                    "\\.",
 | 
				
			||||||
 | 
					                    "::<",
 | 
				
			||||||
 | 
					                    "::",
 | 
				
			||||||
 | 
					                    ":",
 | 
				
			||||||
 | 
					                ].map((kw) => `(?:${kw})`).join("|")
 | 
				
			||||||
 | 
					            })`,
 | 
				
			||||||
 | 
					            "g",
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    addMatches(
 | 
				
			||||||
 | 
					        colors.colorNumber,
 | 
				
			||||||
 | 
					        /(0|(?:[1-9][0-9]*)|(?:0[0-7]+)|(?:0x[0-9a-fA-F]+)|(?:0b[01]+))/g,
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    addMatches(
 | 
				
			||||||
 | 
					        colors.colorFunction,
 | 
				
			||||||
 | 
					        /([a-zA-Z_]\w*(?=\())/g,
 | 
				
			||||||
 | 
					        "font-weight: 700;",
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    addMatches(colors.colorIdentifier, /([a-z_]\w*)/g);
 | 
				
			||||||
 | 
					    addMatches(colors.colorType, /([A-Z_]\w*)/g);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    matches = matches.reduce<typeof matches>(
 | 
				
			||||||
 | 
					        (acc, match) =>
 | 
				
			||||||
 | 
					            acc.find((m) => m.index === match.index) === undefined
 | 
				
			||||||
 | 
					                ? (acc.push(match), acc)
 | 
				
			||||||
 | 
					                : acc,
 | 
				
			||||||
 | 
					        [],
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    matches.sort((a, b) => a.index - b.index);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let highlighted = "";
 | 
				
			||||||
 | 
					    let i = 0;
 | 
				
			||||||
 | 
					    for (const match of matches) {
 | 
				
			||||||
 | 
					        if (match.index < i) {
 | 
				
			||||||
 | 
					            continue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        while (i < match.index) {
 | 
				
			||||||
 | 
					            highlighted += code[i];
 | 
				
			||||||
 | 
					            i += 1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        const section = code.slice(match.index, match.index + match.length);
 | 
				
			||||||
 | 
					        highlighted +=
 | 
				
			||||||
 | 
					            `<span style="color: ${match.color};${match.extra}">${section}</span>`;
 | 
				
			||||||
 | 
					        i += section.length;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    while (i < code.length) {
 | 
				
			||||||
 | 
					        highlighted += code[i];
 | 
				
			||||||
 | 
					        i += 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return highlighted;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function sourceCode(view: Element, codeData: string) {
 | 
					function sourceCode(view: Element, codeData: string) {
 | 
				
			||||||
    const outerContainer = document.createElement("div");
 | 
					    const outerContainer = document.createElement("div");
 | 
				
			||||||
    outerContainer.classList.add("code-container");
 | 
					    outerContainer.classList.add("code-container");
 | 
				
			||||||
@ -51,7 +245,7 @@ function sourceCode(view: Element, codeData: string) {
 | 
				
			|||||||
    const code = document.createElement("pre");
 | 
					    const code = document.createElement("pre");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    code.classList.add("code-source");
 | 
					    code.classList.add("code-source");
 | 
				
			||||||
    code.innerText = codeData;
 | 
					    code.innerHTML = syntaxHighlight(codeData);
 | 
				
			||||||
    innerContainer.append(lines, code);
 | 
					    innerContainer.append(lines, code);
 | 
				
			||||||
    outerContainer.append(innerContainer);
 | 
					    outerContainer.append(innerContainer);
 | 
				
			||||||
    view.replaceChildren(outerContainer);
 | 
					    view.replaceChildren(outerContainer);
 | 
				
			||||||
 | 
				
			|||||||
@ -11,6 +11,10 @@
 | 
				
			|||||||
    --white: #ecebe9;
 | 
					    --white: #ecebe9;
 | 
				
			||||||
    --white-transparent: #ecebe9aa;
 | 
					    --white-transparent: #ecebe9aa;
 | 
				
			||||||
    --code-status: var(--white);
 | 
					    --code-status: var(--white);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    --code-bg: #282828;
 | 
				
			||||||
 | 
					    --code-fg: #fbf1c7;
 | 
				
			||||||
 | 
					    --code-linenr: #7c6f64;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
* {
 | 
					* {
 | 
				
			||||||
@ -99,11 +103,21 @@ main #cover {
 | 
				
			|||||||
#view .code-container {
 | 
					#view .code-container {
 | 
				
			||||||
    max-height: 100%;
 | 
					    max-height: 100%;
 | 
				
			||||||
    overflow: scroll;
 | 
					    overflow: scroll;
 | 
				
			||||||
    background-color: rgba(255, 255, 255, 0.1);
 | 
					    background-color: var(--code-bg);
 | 
				
			||||||
    padding: 0.5rem;
 | 
					    padding: 0.5rem;
 | 
				
			||||||
    border-radius: 0.5rem;
 | 
					    border-radius: 0.5rem;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#view .code-container pre {
 | 
				
			||||||
 | 
					    font-family: "Roboto Mono", monospace;
 | 
				
			||||||
 | 
					    font-weight: 500;
 | 
				
			||||||
 | 
					    color: var(--code-fg);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#view .code-container pre.code-lines {
 | 
				
			||||||
 | 
					    color: var(--code-linenr);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#view .code-container.code-coverage {
 | 
					#view .code-container.code-coverage {
 | 
				
			||||||
    max-height: calc(100% - 103px);
 | 
					    max-height: calc(100% - 103px);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -116,7 +130,6 @@ main #cover {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#view .code-lines {
 | 
					#view .code-lines {
 | 
				
			||||||
    color: var(--white-transparent);
 | 
					 | 
				
			||||||
    border-right: 1px solid currentcolor;
 | 
					    border-right: 1px solid currentcolor;
 | 
				
			||||||
    padding-right: 0.5rem;
 | 
					    padding-right: 0.5rem;
 | 
				
			||||||
    margin: 0;
 | 
					    margin: 0;
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user