From 219785e465b4a36b6a61bd0196de7bd212297eeb Mon Sep 17 00:00:00 2001 From: Mikkel Kongsted Date: Fri, 13 Dec 2024 16:03:01 +0100 Subject: [PATCH] everything --- compiler/arch.ts | 2 + compiler/checker.ts | 15 +- compiler/lowerer.ts | 20 +- editors/vscode/syntaxes/slige.tmLanguage.json | 78 +++++++ examples/advent_of_code/day2.slg | 190 ++++++++++++++++++ examples/example_3.slg | 38 ++++ runtime/Makefile | 13 +- runtime/actions.hpp | 2 +- runtime/alloc.hpp | 7 + runtime/arch.hpp | 2 + runtime/main.cpp | 2 +- runtime/value.hpp | 7 + runtime/vm.cpp | 35 +++- 13 files changed, 392 insertions(+), 19 deletions(-) create mode 100644 examples/advent_of_code/day2.slg create mode 100644 examples/example_3.slg diff --git a/compiler/arch.ts b/compiler/arch.ts index e1c51e6..1c297e7 100644 --- a/compiler/arch.ts +++ b/compiler/arch.ts @@ -38,11 +38,13 @@ export const Ops = { export type Builtins = typeof Builtins; export const Builtins = { + IntToString: 0x00, StringConcat: 0x10, StringEqual: 0x11, StringCharAt: 0x12, StringLength: 0x13, StringPushChar: 0x14, + StringToInt: 0x15, ArrayNew: 0x20, ArraySet: 0x21, ArrayPush: 0x22, diff --git a/compiler/checker.ts b/compiler/checker.ts index fc950cf..1c894ea 100644 --- a/compiler/checker.ts +++ b/compiler/checker.ts @@ -198,8 +198,8 @@ export class Checker { } case "index": { const subject = this.checkExpr(stmt.kind.subject.kind.subject); - if (subject.type !== "array") { - this.report("cannot index on non-array", pos); + if (subject.type !== "array" && subject.type !== "string") { + this.report(`cannot index on non-array, got: ${subject.type}`, pos); return { type: "error" }; } const indexValue = this.checkExpr(stmt.kind.subject.kind.value); @@ -207,7 +207,7 @@ export class Checker { this.report("cannot index on array with non-int", pos); return { type: "error" }; } - if (!vtypesEqual(subject.inner, value)) { + if (subject.type == "array" && !vtypesEqual(subject.inner, value)) { this.report( `cannot assign incompatible type to array ` + `'${vtypeToString(subject)}'` + @@ -345,8 +345,8 @@ export class Checker { } const pos = expr.pos; const subject = this.checkExpr(expr.kind.subject); - if (subject.type !== "array") { - this.report("cannot index on non-array", pos); + if (subject.type !== "array" && subject.type !== "string") { + this.report(`cannot index on non-array, got: ${subject.type}`, pos); return { type: "error" }; } const value = this.checkExpr(expr.kind.value); @@ -354,7 +354,10 @@ export class Checker { this.report("cannot index on array with non-int", pos); return { type: "error" }; } - return subject.inner; + if (subject.type === "array") { + return subject.inner; + } + return { type: "int" } } public checkCallExpr(expr: Expr): VType { diff --git a/compiler/lowerer.ts b/compiler/lowerer.ts index dde41e2..aea880e 100644 --- a/compiler/lowerer.ts +++ b/compiler/lowerer.ts @@ -224,7 +224,7 @@ export class Lowerer { case "field": break; case "index": - break; + return this.lowerIndexExpr(expr); case "call": return this.lowerCallExpr(expr); case "unary": @@ -241,6 +241,24 @@ export class Lowerer { throw new Error(`unhandled expr '${expr.kind.type}'`); } + private lowerIndexExpr(expr: Expr) { + if (expr.kind.type !== "index") { + throw new Error(); + } + this.lowerExpr(expr.kind.subject) + this.lowerExpr(expr.kind.value) + + if (expr.kind.subject.vtype?.type == "array") { + this.program.add(Ops.Builtin, Builtins.ArrayAt); + return; + } + if (expr.kind.subject.vtype?.type == "string") { + this.program.add(Ops.Builtin, Builtins.StringCharAt); + return; + } + throw new Error(`unhandled index subject type '${expr.kind.subject}'`); + } + private lowerSymExpr(expr: Expr) { if (expr.kind.type !== "sym") { throw new Error(); diff --git a/editors/vscode/syntaxes/slige.tmLanguage.json b/editors/vscode/syntaxes/slige.tmLanguage.json index 871b1aa..9791c78 100644 --- a/editors/vscode/syntaxes/slige.tmLanguage.json +++ b/editors/vscode/syntaxes/slige.tmLanguage.json @@ -1,4 +1,5 @@ { +<<<<<<< HEAD "$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json", "name": "Slige", "patterns": [ @@ -12,6 +13,83 @@ ], "repository": { "keywords": { +======= + "$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json", + "name": "Slige", + "patterns": [ + { "include": "#comments" }, + { "include": "#keywords" }, + { "include": "#strings" }, + { "include": "#numbers" }, + { "include": "#operators" }, + { "include": "#punctuation" }, + { "include": "#functions" }, + { "include": "#idents" } + ], + "repository": { + "comments": { + "patterns": [ + { + "name": "comment.line.slige", + "begin": "//", + "end": "\\n" + }, + { + "name": "comment.block.slige", + "begin": "/\\*", + "end": "\\*/" + } + ] + }, + "keywords": { + "patterns": [ + { + "name": "keyword.control.slige", + "match": "\\b(break|return|let|fn|loop|if|else|struct|import|or|and|not)\\b" + }, + { + "name": "constant.language.slige", + "match": "\\b(null|false|true)\\b" + }, + { + "name": "storage.type.slige", + "match": "\\b(int|string|bool)\\b" + } + ] + }, + "strings": { + "name": "string.quoted.double.slige", + "begin": "\"", + "end": "\"", + "patterns": [ + { + "name": "constant.character.escape.slige", + "match": "\\\\." + } + ] + }, + "numbers": { + "patterns": [ + { + "name": "constant.numeric.slige", + "match": "\\b0\\b" + }, + { + "name": "constant.numeric.slige", + "match": "\\b[1-9][0-9]*(\\.[0-9]+)?\\b" + }, + { + "name": "constant.numeric.slige", + "match": "\\b0x[0-9a-fA-F]+?\\b" + }, + { + "name": "constant.numeric.slige", + "match": "\\b0b[01]+?\\b" + } + ] + }, + "operators": { +>>>>>>> 53a965f (everything) "patterns": [ { "name": "keyword.control.slige", diff --git a/examples/advent_of_code/day2.slg b/examples/advent_of_code/day2.slg new file mode 100644 index 0000000..1a2a537 --- /dev/null +++ b/examples/advent_of_code/day2.slg @@ -0,0 +1,190 @@ + + +fn print(msg: string) #[builtin(Print)] {} +fn println(msg: string) { print(msg + "\n") } + +fn int_to_string(number: int) -> string #[builtin(IntToString)] {} + +fn string_push_char(str: string, value: int) -> string #[builtin(StringPushChar)] {} +fn string_length(str: string) -> int #[builtin(StringLength)] {} +fn string_to_int(str: string) -> int #[builtin(StringToInt)] {} + +fn array_new_string() -> [string] #[builtin(ArrayNew)] {} +fn array_new_int() -> [int] #[builtin(ArrayNew)] {} +fn array_push_string(array: [string], value: string) #[builtin(ArrayPush)] {} +fn array_push_int(array: [int], value: int) #[builtin(ArrayPush)] {} +fn array_length_string(array: [string]) -> int #[builtin(ArrayLength)] {} +fn array_length_int(array: [int]) -> int #[builtin(ArrayLength)] {} + +fn char(ch: string) -> int { + ch[0] +} + +fn abs(number: int) -> int { + let result = number; + if number < 0 { + result = number - (number * 2); + } + result +} + +fn split(str: string, seperator: int) -> [string] { + let result: [string] = array_new_string(); + + let i = 0; + let current_str = ""; + loop { + if i >= string_length(str) { + break; + } + let char = str[i]; + if char == seperator { + array_push_string(result, current_str); + current_str = ""; + } else { + current_str = string_push_char(current_str, char); + } + i = i + 1; + } + array_push_string(result, current_str); + result +} + +fn slice(str: string, from: int, to: int) -> string { + let result = ""; + let i = from; + loop { + if i >= string_length(str) { + break; + } + if i >= to { + break; + } + result = string_push_char(result, str[i]); + i = i + 1; + } + result +} + +// fn triangle_sort(array: [int]) -> [int] { +// let result: [int] = array_new_int(); +// let i = 0; +// loop { +// if i >= array_length_int(array) { +// break; +// } +// let j = i; +// let current_lowest_int = array[0]; +// loop { +// if j >= array_length_int(array) { +// break; +// } +// let current_int = array[j]; +// if current_int < current_lowest_int { +// current_lowest_int = current_int; +// } +// j = j + 1; +// } +// array_push_int(result, current_lowest_int); +// i = i + 1; +// } +// result +// } + +fn array_clone(array: [int]) -> [int] { + let len = array_length_int(array); + let result = array_new_int(); + let i = 0; + loop { + if i >= len { break; } + result[i] = array[i]; + i = 1 + 1; + } + result +} + +fn array_sort_mut(array: [int]) { + let len = array_length_int(array); + let i = 0; + loop { + if i >= len { break; } + let j = i + 1; + loop { + if j >= len { break; } + if array[j] < array[i] { + let tmp = array[j]; + array[j] = array[i]; + array[i] = tmp; + } + j = j + 1; + } + i = 1 + 1; + } +} + +fn array_to_sorted(array: [int]) -> [int] { + let cloned = array_clone(array); + array_sort_mut(array); + cloned +} + +fn location_ids() -> string { +"49744 57964 +20738 85861 +20319 65072 +79568 74248 +78194 83454 +48701 94102 +69552 26808 +62781 67392 +85323 47428 +99344 72568 +27523 97243 +48039 36600 +91532 31571 +21306 31571 +52409 10805 +33901 31571 +80772 38756 +13849 54584 +72294 28326 +86065 65553 +93987 72533 +81640 39741 +25701 89912 +98611 57082 +80949 94974 +84717 61876 +31599 57082 +87119 65871 +56659 22897" +} + +fn main() { + let location_ids = split(location_ids(), char("\n")); + let i = 0; + let left_ids: [int] = array_new_int(); + let right_ids: [int] = array_new_int(); + loop { + if i >= array_length_string(location_ids) { + break; + } + array_push_int(left_ids, string_to_int(slice(location_ids[i], 0, 5))); + array_push_int(right_ids, string_to_int(slice(location_ids[i], 8, 13))); + i = i + 1; + } + + let sorted_left_ids: [int] = array_to_sorted(left_ids); + // let sorted_right_ids: [int] = array_to_sorted(right_ids); + // i = 0; + // let sum = 0; + // loop { + // if i >= array_length_int(left_ids) { + // break; + // } + // let difference = abs(sorted_left_ids[i] - sorted_right_ids[i]); + // let sum = sum + difference; + // i = i + 1; + // } + // println(int_to_string(sum)) +} diff --git a/examples/example_3.slg b/examples/example_3.slg new file mode 100644 index 0000000..ce182c2 --- /dev/null +++ b/examples/example_3.slg @@ -0,0 +1,38 @@ +fn print(msg: string) #[builtin(Print)] {} +fn println(msg: string) { print(msg + "\n") } + +fn array_length_int(array: [int]) -> int #[builtin(ArrayLength)] {} +fn array_new_int() -> [int] #[builtin(ArrayNew)] {} +fn array_push_int(array: [int], value: int) #[builtin(ArrayPush)] {} + +fn int_to_string(number: int) -> string #[builtin(IntToString)] {} + +fn add(a: int, b: int) -> int { + a + b +} + +fn main() -> int { + let result = 0; + let array = array_new_int(); + + let i = 0; + loop { + if i >= 10 { + break; + } + + array_push_int(array, i); + i = i + 1; + } + i = 0; + loop { + if i >= array_length_int(array) { + break; + } + result = add(array[i], array[i]); + println(int_to_string(result)); + i = i + 1; + } + result +} + diff --git a/runtime/Makefile b/runtime/Makefile index 99a1669..67e31b4 100644 --- a/runtime/Makefile +++ b/runtime/Makefile @@ -1,10 +1,19 @@ +# CXX_FLAGS = \ +# -std=c++23 \ +# -Og \ +# -fsanitize=address,undefined \ +# -pedantic -pedantic-errors \ +# -Wall -Wextra -Wpedantic -Wconversion -Werror \ + + CXX_FLAGS = \ -std=c++23 \ - -Og \ -fsanitize=address,undefined \ + -Og \ -pedantic -pedantic-errors \ - -Wall -Wextra -Wpedantic -Wconversion \ + -Wall -Wextra -Wpedantic -Wconversion -Werror \ + OUT=build/sliger diff --git a/runtime/actions.hpp b/runtime/actions.hpp index a19ba14..cab5dd2 100644 --- a/runtime/actions.hpp +++ b/runtime/actions.hpp @@ -38,7 +38,7 @@ private: std::vector instructions; }; -static auto action_from_json( +static inline auto action_from_json( std::unique_ptr value) -> std::unique_ptr { auto& obj = value->as(); diff --git a/runtime/alloc.hpp b/runtime/alloc.hpp index 2fbf94b..a4bc9fe 100644 --- a/runtime/alloc.hpp +++ b/runtime/alloc.hpp @@ -13,6 +13,13 @@ namespace sliger::heap { struct Array { std::vector values; + inline auto at(int32_t index)& -> Value& { + if (index >= static_cast(this->values.size()) || index < 0) { + std::cout << std::format("index not in range, expected to be in range (0..{}), got: {}", this->values.size(), index); + exit(1); + } + return values.at(index); + } }; struct Struct { diff --git a/runtime/arch.hpp b/runtime/arch.hpp index c2d5b4b..c484a41 100644 --- a/runtime/arch.hpp +++ b/runtime/arch.hpp @@ -39,11 +39,13 @@ enum class Op : uint32_t { }; enum class Builtin : uint32_t { + IntToString = 0x00, StringConcat = 0x10, StringEqual = 0x11, StringCharAt = 0x12, StringLength = 0x13, StringPushChar = 0x14, + StringToInt = 0x15, ArrayNew = 0x20, ArraySet = 0x21, ArrayPush = 0x22, diff --git a/runtime/main.cpp b/runtime/main.cpp index 1529b22..ce28b71 100644 --- a/runtime/main.cpp +++ b/runtime/main.cpp @@ -9,7 +9,7 @@ #include #include -bool print_stack_debug = false; +bool print_stack_debug = true; int execute_file_and_exit(std::string filename) { diff --git a/runtime/value.hpp b/runtime/value.hpp index 4860983..7380d52 100644 --- a/runtime/value.hpp +++ b/runtime/value.hpp @@ -70,6 +70,13 @@ struct Bool { }; struct String { std::string value; + inline auto at(int32_t index) -> int32_t { + if (index >= static_cast(this->value.length()) || index < 0) { + std::cout << std::format("index not in range, expected to be in range (0..{}), got: {}", this->value.length()-1, index); + exit(1); + } + return this->value.at(index); + } }; struct Ptr { uint32_t value; diff --git a/runtime/vm.cpp b/runtime/vm.cpp index 9812503..1324d13 100644 --- a/runtime/vm.cpp +++ b/runtime/vm.cpp @@ -285,6 +285,14 @@ void VM::run_builtin(Builtin builtin_id) "Running builtin {}\n", static_cast(builtin_id)); } switch (builtin_id) { + case Builtin::IntToString: { + assert_stack_has(1); + auto number = static_cast(stack_pop().as_int().value); + auto str = std::to_string(number); + stack_push(String(str)); + break; + } + case Builtin::StringConcat: { assert_stack_has(2); auto right = stack_pop(); @@ -303,11 +311,10 @@ void VM::run_builtin(Builtin builtin_id) 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)); + auto string_value = stack_pop(); + auto index = static_cast(index_value.as_int().value); + auto string = string_value.as_string(); + stack_push(Int(string.at(index))); break; } case Builtin::StringLength: { @@ -328,6 +335,14 @@ void VM::run_builtin(Builtin builtin_id) stack_push(String(new_str)); break; } + case Builtin::StringToInt: { + assert_stack_has(1); + auto str = stack_pop().as_string().value; + auto number = atoi(str.c_str()); + stack_push(Int(number)); + break; + } + case Builtin::ArrayNew: { auto alloc_res = this->heap.alloc(); stack_push(Ptr(alloc_res.val())); @@ -335,8 +350,12 @@ void VM::run_builtin(Builtin builtin_id) } case Builtin::ArraySet: { assert_stack_has(2); - std::cerr << std::format("not implemented\n"); - std::exit(1); + auto index = stack_pop().as_int().value; + auto array_ptr = stack_pop().as_ptr().value; + auto value = stack_pop(); + auto array = this->heap.at(array_ptr).val()->as_array(); + array.at(index) = value; + stack_push(Null()); break; } case Builtin::ArrayPush: { @@ -354,7 +373,7 @@ void VM::run_builtin(Builtin builtin_id) 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))); + stack_push(array.at(index)); break; } case Builtin::ArrayLength: {