From 18eddd82a4bfbd53c5eabce2f78d21a7aecc0ace Mon Sep 17 00:00:00 2001 From: sfja Date: Fri, 13 Dec 2024 06:09:10 +0100 Subject: [PATCH] fix call stuff --- compiler/arch.ts | 81 ++------------------ compiler/info.ts | 2 +- compiler/lowerer.ts | 85 ++++++++++----------- examples/std.slg | 29 ++++---- examples/string_int_args.slg | 25 +++++++ runtime/vm.cpp | 140 +++++++++++++++++++---------------- runtime/vm.hpp | 4 +- 7 files changed, 163 insertions(+), 203 deletions(-) create mode 100644 examples/string_int_args.slg diff --git a/compiler/arch.ts b/compiler/arch.ts index 7ada7dd..e1c51e6 100644 --- a/compiler/arch.ts +++ b/compiler/arch.ts @@ -50,85 +50,16 @@ export const Builtins = { ArrayLength: 0x24, StructSet: 0x30, Print: 0x40, - } as const; export function opToString(op: number): string { - switch (op) { - case Ops.Nop: - return "Nop"; - case Ops.PushNull: - return "PushNull"; - case Ops.PushInt: - return "PushInt"; - case Ops.PushBool: - return "PushBool"; - case Ops.PushString: - return "PushString"; - case Ops.PushPtr: - return "PushPtr"; - case Ops.Pop: - return "Pop"; - case Ops.ReserveStatic: - return "ReserveStatic"; - case Ops.LoadStatic: - return "LoadStatic"; - case Ops.StoreStatic: - return "StoreStatic"; - case Ops.LoadLocal: - return "LoadLocal"; - case Ops.StoreLocal: - return "StoreLocal"; - case Ops.Call: - return "Call"; - case Ops.Return: - return "Return"; - case Ops.Jump: - return "Jump"; - case Ops.JumpIfTrue: - return "JumpIfTrue"; - case Ops.Builtin: - return "Builtin"; - case Ops.Add: - return "Add"; - case Ops.Subtract: - return "Subtract"; - case Ops.Multiply: - return "Multiply"; - case Ops.Divide: - return "Divide"; - case Ops.Remainder: - return "Remainder"; - case Ops.Equal: - return "Equal"; - case Ops.LessThan: - return "LessThan"; - case Ops.And: - return "And"; - case Ops.Or: - return "Or"; - case Ops.Xor: - return "Xor"; - case Ops.Not: - return "Not"; - case Ops.SourceMap: - return "SourceMap"; - default: - return ``; - } + return Object.entries(Ops) + .find(([_key, value]) => value === op) + ?.[0] ?? ``; } export function builtinToString(builtin: number): string { - switch (builtin) { - case Builtins.StringConcat: return "StringConcat"; - case Builtins.StringEqual: return "StringEqual"; - case Builtins.StringCharAt: return "StringCharAt"; - case Builtins.StringLength: return "StringLength"; - case Builtins.StringPushChar: return "StringPushChar"; - case Builtins.ArraySet: return "ArraySet"; - case Builtins.StructSet: return "StructSet"; - case Builtins.Print: return "Print"; - default: - return ``; - } + return Object.entries(Builtins) + .find(([_key, value]) => value === builtin) + ?.[0] ?? ``; } diff --git a/compiler/info.ts b/compiler/info.ts index 07b2ca8..55a3dad 100644 --- a/compiler/info.ts +++ b/compiler/info.ts @@ -19,7 +19,7 @@ export class Reporter { private printReport({ reporter, type, pos, msg }: Report) { console.error( - `${reporter}: ${type}: ${msg}${ + `${reporter} ${type}: ${msg}${ pos ? ` at ${pos.line}:${pos.col}` : "" }`, ); diff --git a/compiler/lowerer.ts b/compiler/lowerer.ts index 80beeb5..6f78e42 100644 --- a/compiler/lowerer.ts +++ b/compiler/lowerer.ts @@ -113,7 +113,8 @@ export class Lowerer { if (stmt.kind.expr) { this.lowerExpr(stmt.kind.expr); } - this.program.add(Ops.Jump, this.breakStack.at(-1)!); + this.program.add(Ops.PushPtr, this.breakStack.at(-1)!); + this.program.add(Ops.Jump); } private lowerBuiltinAnno(annoArgs: Expr[]) { @@ -127,49 +128,15 @@ export class Lowerer { ); } const value = anno.kind.value; - switch (value) { - case "Print": { - this.program.add(Ops.Builtin, Builtins.Print); - break; - } - case "StringLength": { - this.program.add(Ops.Builtin, Builtins.StringLength); - break; - } - case "StringCharAt": { - this.program.add(Ops.Builtin, Builtins.StringCharAt); - break; - } - case "StringPushChar": { - this.program.add(Ops.Builtin, Builtins.StringPushChar); - break; - } - case "ArrayNew": { - this.program.add(Ops.Builtin, Builtins.ArrayNew); - break; - } - case "ArraySet": { - this.program.add(Ops.Builtin, Builtins.ArraySet); - break; - } - case "ArrayPush": { - this.program.add(Ops.Builtin, Builtins.ArrayPush); - break; - } - case "ArrayLength": { - this.program.add(Ops.Builtin, Builtins.ArrayLength); - break; - } - case "ArrayAt": { - this.program.add(Ops.Builtin, Builtins.ArrayAt); - break; - } - default: { - throw new Error( - `unrecognized builtin '${value}'`, - ); - } + const builtin = Object.entries(Builtins).find((entry) => + entry[0] === value + )?.[1]; + if (builtin === undefined) { + throw new Error( + `unrecognized builtin '${value}'`, + ); } + this.program.add(Ops.Builtin, builtin); } private lowerFnStmt(stmt: Stmt) { @@ -238,7 +205,7 @@ export class Lowerer { case "ident": break; case "group": - break; + return void this.lowerExpr(expr.kind.expr); case "field": break; case "index": @@ -246,7 +213,7 @@ export class Lowerer { case "call": return this.lowerCallExpr(expr); case "unary": - break; + return this.lowerUnaryExpr(expr); case "binary": return this.lowerBinaryExpr(expr); case "if": @@ -299,6 +266,28 @@ export class Lowerer { this.program.add(Ops.PushString, expr.kind.value); } + private lowerUnaryExpr(expr: Expr) { + if (expr.kind.type !== "unary") { + throw new Error(); + } + this.lowerExpr(expr.kind.subject); + const vtype = expr.kind.subject.vtype!; + if (vtype.type === "bool") { + switch (expr.kind.unaryType) { + case "not": + this.program.add(Ops.Not); + return; + default: + } + } + throw new Error( + `unhandled unary` + + ` '${vtypeToString(expr.vtype!)}' aka. ` + + ` ${expr.kind.unaryType}` + + ` '${vtypeToString(expr.kind.subject.vtype!)}'`, + ); + } + private lowerBinaryExpr(expr: Expr) { if (expr.kind.type !== "binary") { throw new Error(); @@ -320,6 +309,9 @@ export class Lowerer { case "==": this.program.add(Ops.Equal); return; + case "<": + this.program.add(Ops.LessThan); + return; case ">=": this.program.add(Ops.LessThan); this.program.add(Ops.Not); @@ -403,7 +395,8 @@ export class Lowerer { this.program.setLabel(contineLabel); this.lowerExpr(expr.kind.body); - this.program.add(Ops.PushPtr, breakLabel); + this.program.add(Ops.Pop); + this.program.add(Ops.PushPtr, contineLabel); this.program.add(Ops.Jump); this.program.setLabel(breakLabel); if (expr.vtype!.type === "null") { diff --git a/examples/std.slg b/examples/std.slg index 549699f..9c82740 100644 --- a/examples/std.slg +++ b/examples/std.slg @@ -1,19 +1,16 @@ -fn array_new_string() -> [string] #[builtin(ArrayNew)] {} fn print(msg: string) #[builtin(Print)] {} +fn println(msg: string) { print(msg + "\n") } -fn array_push_string(array: [string], str: string) #[builtin(ArrayPush)] {} - -fn string_push_char(str: string, value: int) #[builtin(StringPushChar)] {} - +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 array_string_length(array: [string]) -> int #[builtin(StringLength)] {} - -fn array_string_at(array: [string], index: int) -> string #[builtin(ArrayAt)] {} +fn array_new_string() -> [string] #[builtin(ArrayNew)] {} +fn array_push_string(array: [string], value: string) #[builtin(ArrayPush)] {} +fn array_length_string(array: [string]) -> int #[builtin(ArrayLength)] {} +fn array_at_string(array: [string], index: int) -> string #[builtin(ArrayAt)] {} fn char(ch: string) -> int { string_char_at(ch, 0) @@ -25,6 +22,9 @@ fn split(str: string, seperator: int) -> [string] { let i = 0; let current_str = ""; loop { + if i >= string_length(str) { + break; + } let char = string_char_at(str, i); if char == seperator { array_push_string(result, current_str); @@ -32,9 +32,6 @@ fn split(str: string, seperator: int) -> [string] { } else { string_push_char(current_str, char); } - if string_length(str) - 1 == i { - break; - } i = i + 1; } result @@ -43,11 +40,13 @@ fn split(str: string, seperator: int) -> [string] { fn main() { let array = split("aoisfjasoifjsaiofjsa", char("a")); let i = 0; + let array_length = array_length_string(array); loop { - print(array_string_at(array, i) + "\n"); - i = i + 1; - if array_string_length(array) - 1 == i { + if i >= array_length { break; } + let v = array_at_string(array, 0); + println(v); + i = i + 1; } } diff --git a/examples/string_int_args.slg b/examples/string_int_args.slg new file mode 100644 index 0000000..310fef2 --- /dev/null +++ b/examples/string_int_args.slg @@ -0,0 +1,25 @@ + +fn print(msg: string) #[builtin(Print)] {} + +fn repeat(value: string, amount: int) -> string { + let result = ""; + + let i = 0; + loop { + if not (i < amount) { + break; + } + + result = result + value; + + i = i + 1; + } + + result +} + +fn main() { + let value = repeat("hello world\n", 3); + print(value); +} + diff --git a/runtime/vm.cpp b/runtime/vm.cpp index 503e77d..9812503 100644 --- a/runtime/vm.cpp +++ b/runtime/vm.cpp @@ -30,8 +30,13 @@ void VM::run_n_instructions(size_t amount) void VM::run_instruction() { if (this->opts.print_stack_debug) { + // std::cout << std::format(" {:>4}: {:<12}{}\n", this->pc, + // maybe_op_to_string(this->program[this->pc]), + // stack_repr_string(8)); + auto stack_frame_size = this->stack.size() - this->bp; std::cout << std::format(" {:>4}: {:<12}{}\n", this->pc, - maybe_op_to_string(this->program[this->pc]), stack_repr_string(8)); + maybe_op_to_string(this->program[this->pc]), + stack_repr_string(stack_frame_size)); } auto op = eat_op(); switch (op) { @@ -125,11 +130,9 @@ void VM::run_instruction() stack_push(Ptr { .value = this->bp }); this->pc = fn_ptr.as_ptr().value; this->bp = static_cast(this->stack.size()); - // for (size_t i = arguments.size(); i > 0; --i) { - // stack_push(std::move(arguments.at(i - 1))); - // } - for (size_t i = 0; i < arguments.size(); ++i) { - stack_push(std::move(arguments.at(i))); + for (auto&& arg = arguments.rbegin(); arg != arguments.rend(); + ++arg) { + stack_push(*arg); } if (this->opts.flame_graph) { this->flame_graph.report_call( @@ -277,20 +280,57 @@ void VM::run_instruction() void VM::run_builtin(Builtin builtin_id) { + if (this->opts.print_stack_debug) { + std::cout << std::format( + "Running builtin {}\n", static_cast(builtin_id)); + } switch (builtin_id) { case Builtin::StringConcat: { assert_stack_has(2); - auto left = stack_pop(); auto right = stack_pop(); + auto left = stack_pop(); stack_push( - String(right.as_string().value + left.as_string().value)); + String(left.as_string().value + right.as_string().value)); break; } case Builtin::StringEqual: { assert_stack_has(2); - auto left = stack_pop(); auto right = stack_pop(); - stack_push(Bool(right.as_string().value == left.as_string().value)); + auto left = stack_pop(); + stack_push(Bool(left.as_string().value == right.as_string().value)); + break; + } + case Builtin::StringCharAt: { + assert_stack_has(2); + auto index_value = stack_pop(); + auto str = stack_pop(); + + auto index = static_cast(index_value.as_int().value); + auto ch = static_cast(str.as_string().value.at(index)); + stack_push(Int(ch)); + break; + } + case Builtin::StringLength: { + assert_stack_has(1); + auto str = stack_pop().as_string().value; + + auto length = static_cast(str.length()); + stack_push(Int(length)); + break; + } + case Builtin::StringPushChar: { + assert_stack_has(2); + auto ch = stack_pop(); + auto str = stack_pop(); + + auto new_str = std::string(str.as_string().value); + new_str.push_back(static_cast(ch.as_int().value)); + stack_push(String(new_str)); + break; + } + case Builtin::ArrayNew: { + auto alloc_res = this->heap.alloc(); + stack_push(Ptr(alloc_res.val())); break; } case Builtin::ArraySet: { @@ -299,6 +339,32 @@ void VM::run_builtin(Builtin builtin_id) std::exit(1); break; } + case Builtin::ArrayPush: { + assert_stack_has(2); + auto value = stack_pop(); + auto array_ptr = stack_pop().as_ptr().value; + + this->heap.at(array_ptr).val()->as_array().values.push_back(value); + stack_push(Null()); + break; + } + case Builtin::ArrayAt: { + assert_stack_has(2); + auto index = stack_pop().as_int().value; + auto array_ptr = stack_pop().as_ptr().value; + + auto array = this->heap.at(array_ptr).val()->as_array(); + stack_push(array.values.at(static_cast(index))); + break; + } + case Builtin::ArrayLength: { + assert_stack_has(1); + auto array_ptr = stack_pop().as_ptr().value; + + auto array = this->heap.at(array_ptr).val()->as_array(); + stack_push(Int(static_cast(array.values.size()))); + break; + } case Builtin::StructSet: { assert_stack_has(2); std::cerr << std::format("not implemented\n"); @@ -312,59 +378,5 @@ void VM::run_builtin(Builtin builtin_id) stack_push(Null()); break; } - case Builtin::StringCharAt: { - assert_stack_has(2); - auto str = stack_pop(); - auto index_value = stack_pop(); - auto index = static_cast(index_value.as_int().value); - auto ch = static_cast(str.as_string().value.at(index)); - stack_push(Int(ch)); - break; - } - case Builtin::StringLength: { - assert_stack_has(1); - auto str = stack_pop().as_string().value; - auto length = static_cast(str.length()); - stack_push(Int(length)); - break; - } - case Builtin::StringPushChar: { - assert_stack_has(2); - auto str = stack_pop(); - auto ch = stack_pop(); - auto new_str = std::string(str.as_string().value); - new_str.push_back(static_cast(ch.as_int().value)); - stack_push(String(new_str)); - break; - } - case Builtin::ArrayNew: { - auto alloc_res = this->heap.alloc(); - stack_push(Ptr(alloc_res.val())); - break; - } - case Builtin::ArrayPush: { - assert_stack_has(2); - auto array_ptr = stack_pop().as_ptr().value; - auto value = stack_pop(); - auto array = this->heap.at(array_ptr).val()->as_array(); - array.values.push_back(value); - stack_push(Null()); - break; - } - case Builtin::ArrayAt: { - assert_stack_has(2); - auto array_ptr = stack_pop().as_ptr().value; - auto index = stack_pop().as_int().value; - auto array = this->heap.at(array_ptr).val()->as_array(); - stack_push(array.values.at(static_cast(index))); - break; - } - case Builtin::ArrayLength: { - assert_stack_has(1); - auto array_ptr = stack_pop().as_ptr().value; - auto array = this->heap.at(array_ptr).val()->as_array(); - stack_push(Int(static_cast(array.values.size()))); - break; - } } } diff --git a/runtime/vm.hpp b/runtime/vm.hpp index 6adbf69..5a1bc45 100644 --- a/runtime/vm.hpp +++ b/runtime/vm.hpp @@ -185,8 +185,8 @@ public: result += std::format( "{:<11}", stack[stack.size() - i - 1].to_repr_string()); } - if (stack.size() >= max_items) { - result += std::format(" ... + {}", stack.size() - max_items + 1); + if (stack.size() > max_items) { + result += std::format(" ... + {}", stack.size() - max_items); } return result; }