diff --git a/compiler/checker.ts b/compiler/checker.ts index 884fca0..61181c4 100644 --- a/compiler/checker.ts +++ b/compiler/checker.ts @@ -119,8 +119,10 @@ export class Checker { throw new Error(); } - const isBuiltin = stmt.kind.anno && stmt.kind.anno.ident === "builtin"; - if (isBuiltin) { + if ( + stmt.kind.anno?.ident === "remainder" || + stmt.kind.anno?.ident === "builtin" + ) { return; } diff --git a/compiler/desugar/special_loop.ts b/compiler/desugar/special_loop.ts index 5ec1ad8..cb5c5d3 100644 --- a/compiler/desugar/special_loop.ts +++ b/compiler/desugar/special_loop.ts @@ -221,7 +221,7 @@ export class SpecialLoopDesugarer implements AstVisitor { ], }), }), - }), + }, cond.pos), ), Stmt({ type: "expr", diff --git a/compiler/lowerer.ts b/compiler/lowerer.ts index 6feae3f..973eac0 100644 --- a/compiler/lowerer.ts +++ b/compiler/lowerer.ts @@ -12,6 +12,7 @@ export class Lowerer { private locals: Locals = new LocalsFnRoot(); private fnStmtIdLabelMap: { [stmtId: number]: string } = {}; private fnLabelNameMap: { [name: string]: string } = {}; + private returnStack: Label[] = []; private breakStack: Label[] = []; public constructor(private lastPos: Pos) {} @@ -83,7 +84,7 @@ export class Lowerer { case "break": return this.lowerBreakStmt(stmt); case "return": - break; + return this.lowerReturnStmt(stmt); case "fn": return this.lowerFnStmt(stmt); case "let": @@ -128,6 +129,18 @@ export class Lowerer { } } + private lowerReturnStmt(stmt: Stmt) { + if (stmt.kind.type !== "return") { + throw new Error(); + } + if (stmt.kind.expr) { + this.lowerExpr(stmt.kind.expr); + } + this.addClearingSourceMap(); + this.program.add(Ops.PushPtr, this.returnStack.at(-1)!); + this.program.add(Ops.Jump); + } + private lowerBreakStmt(stmt: Stmt) { if (stmt.kind.type !== "break") { throw new Error(); @@ -155,6 +168,9 @@ export class Lowerer { const fnRoot = new LocalsFnRoot(outerLocals); const outerProgram = this.program; + const returnLabel = this.program.makeLabel(); + this.returnStack.push(returnLabel); + this.program = new Assembler(); this.locals = fnRoot; for (const { ident } of stmt.kind.params) { @@ -162,11 +178,16 @@ export class Lowerer { } if (stmt.kind.anno?.ident === "builtin") { this.lowerFnBuiltinBody(stmt.kind.anno.values); + } else if (stmt.kind.anno?.ident === "remainder") { + this.program.add(Ops.Remainder); } else { this.lowerExpr(stmt.kind.body); } this.locals = outerLocals; + this.returnStack.pop(); + this.program.setLabel(returnLabel); + const localAmount = fnRoot.stackReserved() - stmt.kind.params.length; for (let i = 0; i < localAmount; ++i) { @@ -224,7 +245,7 @@ export class Lowerer { case "int": return this.lowerIntExpr(expr); case "bool": - break; + return this.lowerBoolExpr(expr); case "string": return this.lowerStringExpr(expr); case "ident": @@ -300,6 +321,13 @@ export class Lowerer { this.program.add(Ops.PushInt, expr.kind.value); } + private lowerBoolExpr(expr: Expr) { + if (expr.kind.type !== "bool") { + throw new Error(); + } + this.program.add(Ops.PushBool, expr.kind.value); + } + private lowerStringExpr(expr: Expr) { if (expr.kind.type !== "string") { throw new Error(); @@ -375,6 +403,12 @@ export class Lowerer { return; } } + if (vtype.type === "bool") { + if (expr.kind.binaryType === "or") { + this.program.add(Ops.Or); + return; + } + } throw new Error( `unhandled binaryType` + ` '${vtypeToString(expr.vtype!)}' aka. ` + diff --git a/examples/infinite_loop.slg b/examples/infinite_loop.slg new file mode 100644 index 0000000..bb29a58 --- /dev/null +++ b/examples/infinite_loop.slg @@ -0,0 +1,24 @@ + +fn ten_times() { + for (let i = 0; i < 10; i += 1) { + } +} + +fn twenty_times() { + let i = 0; + loop { + if not (i < 20) { + break; + } + i += 1; + } +} + + +fn main() { + loop { + ten_times(); + twenty_times(); + } +} + diff --git a/examples/primes_10000.slg b/examples/primes_10000.slg new file mode 100644 index 0000000..26afc7c --- /dev/null +++ b/examples/primes_10000.slg @@ -0,0 +1,80 @@ + +fn remainder(left: int, right: int) -> int #[remainder()] {} + +fn int_to_string(v: int) -> string #[builtin(IntToString)] {} + +fn string_push_char(str: string, value: int) -> string #[builtin(StringPushChar)] {} +fn string_char_at(str: string, index: int) -> int #[builtin(StringCharAt)] {} +fn string_length(str: string) -> int #[builtin(StringLength)] {} +fn string_to_int(v: string) -> int #[builtin(StringToInt)] {} + +fn string_array_new() -> [string] #[builtin(ArrayNew)] {} +fn string_array_push(array: [string], value: string) #[builtin(ArrayPush)] {} +fn string_array_length(array: [string]) -> int #[builtin(ArrayLength)] {} +fn string_array_at(array: [string], index: int) -> string #[builtin(ArrayAt)] {} + +fn int_array_new() -> [int] #[builtin(ArrayNew)] {} +fn int_array_push(array: [int], value: int) #[builtin(ArrayPush)] {} +fn int_array_length(array: [int]) -> int #[builtin(ArrayLength)] {} +fn int_array_at(array: [int], index: int) -> int #[builtin(ArrayAt)] {} + +fn file_open(filename: string, mode: string) -> int #[builtin(FileOpen)] {} +fn file_close(file: int) #[builtin(FileClose)] {} +fn file_write_string(file: int, content: string) -> int #[builtin(FileWriteString)] {} +fn file_read_char(file: int) -> int #[builtin(FileReadChar)] {} +fn file_read_to_string(file: int) -> string #[builtin(FileReadToString)] {} +fn file_flush(file: int) #[builtin(FileFlush)] {} +fn file_eof(file: int) -> bool #[builtin(FileEof)] {} + +fn stdin() -> int { 0 } +fn stdout() -> int { 1 } +fn stderr() -> int { 2 } + +fn file_read_line(file: int) -> string { + let line = ""; + loop { + if file_eof(file) { + break; + } + let ch = file_read_char(file); + if ch == "\n"[0] { + break; + } + line = string_push_char(line, ch); + } + line +} + +fn print(msg: string) #[builtin(Print)] {} +fn println(msg: string) { print(msg + "\n") } + +fn input(prompt: string) -> string { + print("> "); + file_flush(stdout()); + file_read_line(stdin()) +} + +// + +fn is_prime(n: int) -> bool { + if n == 1 or n == 0{ + return false; + } + + for (let i = 2; i < n; i += 1) { + if remainder(n, i) == 0 { + return false; + } + } + true +} + +fn main() { + for (let i = 1; i < 10000; i += 1) { + if is_prime(i) { + print(int_to_string(i) + " "); + } + } + println(""); +} + diff --git a/runtime/Makefile b/runtime/Makefile index b9b0777..24ae349 100644 --- a/runtime/Makefile +++ b/runtime/Makefile @@ -9,7 +9,7 @@ ifeq ($(RELEASE),1) CXX_FLAGS = \ -std=c++23 \ - -O2 \ + -O3 \ -pedantic -pedantic-errors \ -Wall -Wextra -Wpedantic -Wconversion -Werror\ diff --git a/runtime/vm.hpp b/runtime/vm.hpp index 45c1ff9..299148b 100644 --- a/runtime/vm.hpp +++ b/runtime/vm.hpp @@ -7,8 +7,6 @@ #include #include #include -#include -#include #include #include @@ -89,13 +87,12 @@ private: inline void calculate_node_midway_result(int64_t ic, size_t node_index) { - int64_t diff = ic - this->nodes[this->current].ic_start; - this->nodes[this->current].acc += diff; - this->nodes[this->current].ic_start = ic; - // TODO this was a hack, idk if correct - if (node_index == this->nodes[this->current].parent) + int64_t diff = ic - this->nodes[node_index].ic_start; + this->nodes[node_index].acc += diff; + this->nodes[node_index].ic_start = ic; + if (node_index == 0) return; - calculate_node_midway_result(ic, this->nodes[this->current].parent); + calculate_node_midway_result(ic, this->nodes[node_index].parent); } void fg_node_to_json(json::Writer& writer, size_t node_index) const; diff --git a/web/example.slg b/web/example.slg deleted file mode 100644 index 927726f..0000000 --- a/web/example.slg +++ /dev/null @@ -1,14 +0,0 @@ -fn add(a, b) { - + a b -} - -let result = 0; -let i = 0; -loop { - if >= i 10 { - break; - } - result = add(result, 5); - i = + i 1; -} - diff --git a/web/public/src/index.ts b/web/public/src/index.ts index 22e1ac1..dcc252d 100644 --- a/web/public/src/index.ts +++ b/web/public/src/index.ts @@ -346,9 +346,6 @@ async function main() { view.replaceChildren(outerContainer); }, "code-coverage": async () => { - if (await data.status().then((r) => r.running)) { - return; - } const codeCoverageData = await data.codeCoverageData(); const outerContainer = document.createElement("div"); @@ -375,9 +372,6 @@ async function main() { view.replaceChildren(outerContainer, tooltip); }, "flame-graph": async () => { - if (await data.status().then((r) => r.running)) { - return; - } const flameGraphData = await data.flameGraphData(); const flameGraphFnNames = await data.flameGraphFnNames();