diff --git a/lib/std/core/string.c3 b/lib/std/core/string.c3 index b1d417fda..dc84186c5 100644 --- a/lib/std/core/string.c3 +++ b/lib/std/core/string.c3 @@ -43,8 +43,9 @@ fn String new(char[] c) fn ZString String.zstr(String* str) { - StringData* data = str.data(); if (!str) return (ZString)""; + StringData* data = str.data(); + if (!data) return (ZString)""; if (data.capacity == data.len) { libc::printf("feofk\n"); @@ -63,6 +64,7 @@ fn usize String.len(String* this) if (!*this) return 0; return this.data().len; } + /** * @require new_size <= this.len() */ @@ -87,6 +89,25 @@ fn void String.append_utf32(String* str, Char32[] chars) } } +/** + * @require index < str.len() + **/ +fn void String.set(String* str, usize index, char c) +{ + str.data().chars[index] = c; +} + +fn void String.append_repeat(String* str, char c, usize times) +{ + if (times == 0) return; + str.reserve(times); + StringData* data = str.data(); + for (usize i = 0; i < times; i++) + { + data.chars[data.len++] = c; + } +} + /** * @require c < 0x10ffff */ @@ -174,6 +195,7 @@ fn void String.destroy(String* str) { if (!*str) return; StringData* data = str.data(); + if (!data) return; data.allocator.free(data); *str = (String)null; } diff --git a/resources/examples/binarydigits.c3 b/resources/examples/binarydigits.c3 new file mode 100644 index 000000000..3b3fd415d --- /dev/null +++ b/resources/examples/binarydigits.c3 @@ -0,0 +1,25 @@ +module binarydigits; +import std::math; +import libc; +fn void main() +{ + for (int i = 0; i < 20; i++) + { + String s = bin(i); + defer s.destroy(); + libc::printf("%s\n", s.zstr()); + } +} + +fn String bin(int x) +{ + int bits = 1 + (int)(x == 0 ? 0 : math::log10((double)(x)) / math::log10(2)); + String str; + str.append_repeat('0', bits); + for (int i = 0; i < bits; i++) + { + str.set((usize)(bits - i - 1), x & 1 ? '1' : '0'); + x >>= 1; + } + return str; +} \ No newline at end of file diff --git a/resources/examples/guess_number.c3 b/resources/examples/guess_number.c3 index ae41b0d56..926e71148 100644 --- a/resources/examples/guess_number.c3 +++ b/resources/examples/guess_number.c3 @@ -1,5 +1,4 @@ module guess_number; -import std::mem; import std::io; import libc; @@ -34,7 +33,7 @@ fn int! askGuess(int high) fn char[]! readLine() { char* chars = mem::talloc(1024)?; - isize loaded = getline(&chars, &&(usize)1023, 2libc::stdin()); + isize loaded = getline(&chars, &&(usize)1023, libc::stdin()); if (loaded < 0) return InputResult.FAILED_TO_READ!; chars[loaded] = 0; return chars[0..(loaded - 1)]; diff --git a/resources/examples/notworking/binarydigits.c3 b/resources/examples/notworking/binarydigits.c3 deleted file mode 100644 index edf053129..000000000 --- a/resources/examples/notworking/binarydigits.c3 +++ /dev/null @@ -1,21 +0,0 @@ -module binarydigits; - -fn int main() -{ - fot (int i = 0; i < 20; i++) - { - printf("%s\n", bin(i)); - } -} - -fn string bin(int x) -{ - int bits = (x == 0) ? 1 : log10((double)(x)) / log10(2); - string ret = str.make_repeat('0' as bits); - for (int i = 0; i < bits; i++) - { - ret[bits - i - 1] = x & 1 ? '1' : '0'; - x >>= 1; - } - return ret; -} \ No newline at end of file diff --git a/resources/examples/notworking/map.c3 b/resources/examples/notworking/map.c3 index 5f10fb207..6f4ccb62a 100644 --- a/resources/examples/notworking/map.c3 +++ b/resources/examples/notworking/map.c3 @@ -1,9 +1,14 @@ -module map(Key, Type); +module std::container::map ; + +fault MapResult +{ + KEY_NOT_FOUND +} public struct Entry { Key key; - Type* value; + Type value; usize hash; Entry* next; } @@ -13,34 +18,37 @@ public struct Map usize size; void* map; uint mod; + Allocator allocator; } -public fn Map* Map.init(Map *map) +/** + * @require map != null + **/ +public fn void Map.init(Map *map, Allocator allocator) { - *map = { }; - return map; + map.allocator = allocator; } -public fn Type* Map.valueForKey(Map *map, Key key) +public fn Type! Map.valueForKey(Map *map, Key key) { - if (!map.map) return nil; + if (!map.map) return null; usize hash = key.hash(); usize pos = hash & map.mod; Entry* entry = &map.map[pop]; - if () return nil; + if (!entry) return MapResult.KEY_NOT_FOUND!; while (entry) { if (entry.hash == hash && entry.key == key) return entry.value; entry = entry.next; } - return nil; + return MapResult.KEY_NOT_FOUND!; } -public fn Type *Map.setValueForKey(Map *map, Key key, Type *value) +public fn Type *Map.set(Map *map, Key key, Type value) { if (!map.map) { - map.map = @calloc(Entry, 16); + map.map = allocator.calloc(Entry, 16); map.mod = 0x0F; } @@ -66,42 +74,14 @@ public fn Type *Map.setValueForKey(Map *map, Key key, Type *value) { entry = entry.next; } - entry.next = @malloc(Entry); + entry.next = allocator.alloc(Entry); entry = entry.next; } } -public fn usize Map.size(Vector *vector) +public fn usize Map.size(Map* map) { - return vector.array.size; + return map.size; } -public fn void Map.removeLast(Vector *vector) -{ - vector.array.pop(); -} -public macro Vector.foreach(Vector *vector, macro void(Type value) body) -{ - for (usize i = 0, i < vector.array.size; i++) - { - @body(vector.array[i]); - } -} - -test -{ - define IntVector = Vector(int); - IntVector vector = vector.init(); - vector.add(1); - vector.add(2); - for (int i : vector) - { - printDigit(i); - } - @vector.foreach(int i) - { - printDigit(i); - } - vector.destroy(); -} \ No newline at end of file diff --git a/resources/examples/notworking/retry.c3 b/resources/examples/notworking/retry.c3 deleted file mode 100644 index 07829a273..000000000 --- a/resources/examples/notworking/retry.c3 +++ /dev/null @@ -1,19 +0,0 @@ -module test; - - -public macro retry(#function, int retries = 3) -{ - error e; - while (1) - { - auto! result = #function; - try (result) return result; - catch (e = result); - } while (retries-- > 0) - return e!; -} - -fn void main() -{ - int! result = @retry(eventually_succeed()); -} \ No newline at end of file diff --git a/resources/examples/notworking/swap.c3 b/resources/examples/notworking/swap.c3 deleted file mode 100644 index 8ef12a9ca..000000000 --- a/resources/examples/notworking/swap.c3 +++ /dev/null @@ -1,21 +0,0 @@ -public test; - -/** - * @require parse(a = b), parse(b = a) - */ -public macro void swap(&a, &b) -{ - typeof(a) temp = a; - a = b; - b = temp; -} - -/** - * @require parse(a = b), parse(b = a) - */ -public macro void swap2(auto &a, auto &b) -{ - auto temp = a; - a = b; - b = temp; -} \ No newline at end of file diff --git a/resources/examples/retry.c3 b/resources/examples/retry.c3 new file mode 100644 index 000000000..e1332353c --- /dev/null +++ b/resources/examples/retry.c3 @@ -0,0 +1,44 @@ +module test; +import libc; + +fault TestErr +{ + NOPE +} + +fn int! eventually_succeed() +{ + static int i = 0; + if (i++ < 3) return TestErr.NOPE!; + return i * 3; +} + +macro @retry(#function, int retries = 3) +{ + var $Type = $typeof(#function); + anyerr e; + do + { + $Type! result = #function; + if (catch err = result) + { + e = err; + continue; + } + return result; + } while (retries-- > 0); + return e!; +} + +fn void main() +{ + int! result = @retry(eventually_succeed()); + if (try result) + { + libc::printf("Got result: %d\n", result); + } + else + { + libc::printf("Failed :(\n"); + } +} \ No newline at end of file diff --git a/resources/examples/swap.c3 b/resources/examples/swap.c3 new file mode 100644 index 000000000..54366aaca --- /dev/null +++ b/resources/examples/swap.c3 @@ -0,0 +1,20 @@ +module test; +import libc; + +/** + * @checked a = b, b = a + */ +macro void @swap(&a, &b) +{ + $typeof(a) temp = a; + a = b; + b = temp; +} + +fn void main() +{ + int x = 123; + int y = 456; + @swap(x, y); + libc::printf("x: %d y: %d\n", x, y); +} \ No newline at end of file diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index 50b3f6032..4c72b1430 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -4909,6 +4909,9 @@ void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr) { BEValue no_err; + // Emit the current stack into the thread local or things will get messed up. + if (c->debug.last_ptr) llvm_store(c, c->debug.last_ptr, c->debug.stack_slot, type_alloca_alignment(type_voidptr)); + // 17a. If we used the error var as the indirect recipient, then that will hold the error. // otherwise it's whatever value in be_value. BEValue error_holder = *result_value; @@ -4941,9 +4944,6 @@ void llvm_emit_call_expr(GenContext *c, BEValue *result_value, Expr *expr) // 17f. Emit the "after" block. llvm_emit_block(c, after_block); - // Emit the current stack into the thread local or things will get messed up. - if (c->debug.last_ptr) llvm_store(c, c->debug.last_ptr, c->debug.stack_slot, type_alloca_alignment(type_voidptr)); - // 17g. If void, be_value contents should be skipped. if (!prototype->ret_by_ref) { diff --git a/src/compiler/parse_global.c b/src/compiler/parse_global.c index 43bb8e08f..5e7ea9508 100644 --- a/src/compiler/parse_global.c +++ b/src/compiler/parse_global.c @@ -2113,7 +2113,7 @@ static inline bool parse_doc_contract(ParseContext *c, AstId **docs_ref, DocDire switch (kind) { case DOC_DIRECTIVE_CHECKED: - scratch_buffer_append("@require \""); + scratch_buffer_append("@checked \""); break; case DOC_DIRECTIVE_ENSURE: scratch_buffer_append("@ensure \""); diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index f34c3eda6..f410cbbed 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -1768,6 +1768,7 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s }; if (!sema_expr_analyse_call_invocation(context, call_expr, callee, &failable)) return false; + Expr **args = call_expr->call_expr.arguments; VECEACH(params, i) {