From 2023a7b2d9656f80b00de81453348c0a66f200f7 Mon Sep 17 00:00:00 2001 From: Kimplul Date: Wed, 14 Aug 2024 20:44:26 +0300 Subject: test cleanup + Somewhat poor Git hygiene but I also fixed some bugs while I was at it. --- examples/alloc.ct | 18 ---- examples/arc.ct | 53 ----------- examples/example.ct | 150 ------------------------------ examples/import.ct | 1 - examples/main.ct | 3 - examples/numeral.ct | 35 ------- examples/option.ct | 6 -- examples/res.ek | 1 + examples/std.ct | 35 ------- examples/std.ek | 259 ---------------------------------------------------- examples/v.ct | 12 --- examples/vec.ct | 62 ------------- 12 files changed, 1 insertion(+), 634 deletions(-) delete mode 100644 examples/alloc.ct delete mode 100644 examples/arc.ct delete mode 100644 examples/example.ct delete mode 100644 examples/import.ct delete mode 100644 examples/main.ct delete mode 100644 examples/numeral.ct delete mode 100644 examples/option.ct delete mode 100644 examples/std.ct delete mode 100644 examples/std.ek delete mode 100644 examples/v.ct delete mode 100644 examples/vec.ct (limited to 'examples') diff --git a/examples/alloc.ct b/examples/alloc.ct deleted file mode 100644 index 11eed78..0000000 --- a/examples/alloc.ct +++ /dev/null @@ -1,18 +0,0 @@ -/* from c bindings */ - -pub alloc(s: usize) *void -{ - p: *u8 = malloc(s); - assert(p, "memory allocation failed\n"); - return p; -} - -pub dealloc(p *void) -{ - free(p); -} - -pub realloc(p *, s usize) *void -{ - realloc(p, s); -} diff --git a/examples/arc.ct b/examples/arc.ct deleted file mode 100644 index 8869b42..0000000 --- a/examples/arc.ct +++ /dev/null @@ -1,53 +0,0 @@ -/* could be non-null instead of raw pointer? */ -typedef atomic_rc [t any] { - count *usize; - data *t; -} - -/* macros must be 'called' with () */ -pub define arc(t) { struct (atomic_rc[t]) }; - -pub dereference(a *arc) *#a.data -{ - return a.t; -} - -pub init(mut a *arc, e #a.data) -{ - new(a.count, 0); - a.data = e; -} - -pub init(mut a *arc, b *arc<#a.data>) -{ - copy(a, b); -} - -pub deinit(mut a *arc) -{ - if atomic_fetch_add(a.count, -1) == 1 { - dealloc(a.data); - dealloc(a.count); - } - - a.count = null; - a.data = null; -} - -pub copy(mut a *arc, b *arc<#a.data>) -{ - deinit(a); - a.count = b.count; - a.data = b.data; - atomic_fetch_add(b.count, 1); -} - -pub move(mut a *arc, mut b *arc<#a.data>) -{ - deinit(a); - a.count = b.count; - a.data = b.data; - /* reference count stays the same */ - b.count = null; - a.count = null; -} diff --git a/examples/example.ct b/examples/example.ct deleted file mode 100644 index b5d752f..0000000 --- a/examples/example.ct +++ /dev/null @@ -1,150 +0,0 @@ -/* String example */ - -pub struct string { - len usize; - buf *u8; -} - -pub init(mut s *string) -{ - s.len = 0; - s.buf = null; -} - -pub deinit(mut s *string) -{ - dealloc(s.buf); -} - -pub init(mut s *string, u *u8) -{ - len usize = 0; - r any = u; - while r++ {len++;} - - s.len = len; - s.buf = alloc(s.len); - memcpy(s.buf, u); -} - -pub copy(mut r *string, s *string) *string -{ - dealloc(r.buf); - r.len = s.len; - r.buf = alloc(r.len); - memcpy(r.buf, s.buf); -} - -pub move(mut r *string, mut s *string) *string -{ - dealloc(r.buf); - r.len = s.len; - r.buf = s.buf; - s.buf = null; - s.len = 0; -} - -pub length(s *string) usize -{ - return s.len; -} - -pub index(s *string, i usize) u8 -{ - assert(i < len, "index %zu out of bounds\n", i); - return s.buf[i]; -} - -pub add(r *string, a *string, b *string) -{ - len any = length(a) + length(b); - buf any = alloc(l); - - if r.buf == a.buf { - dealloc(a.buf); - } else if r.buf == b.buf { - dealloc(b.buf); - } - - r.buf = buf; - r.len = len; -} - -/* example of hygienic and recursive macros. - In macros, the last statement of the block is taken as the "return" value, - so the following two definitions would be enough to get the smallest - value of any number of parameters, without affecting any variables in - the parent context. If recursive blocks, the last of the blocks is taken. - - In this case, the same thing could be done with functions of course. - - Internally, if one of these macros is passed as a function argument, all - statements except the last (which has to be a certain type, - have to check exactly which rules I want to apply to it) will be moved - into the nearest "regular" context, i.e. not a function call in a function - call or something like that. The last variable's context is kept as the block - in which it was defined, but accessed "anonymously". In C, something like - - // some counter to make sure we don't overlap some other variable - int min_res_12345; - { - const int _a = a; - const int _b = b; - - const int _res = _a < _b ? _a : _b; - min_res_12345 = _res; - } - call(min_res_12345); - - */ -define min(a, b) {{ - _a const = a; - _b const = b; - - _res const = if _a < _b { - _a - } else { - _b - }; - - _res; -}} - -define min(a, b ...args) {{ - _a const = a; - _b const = min(b, ...args); - - _res const = if _a < _b { - _a - } else { - _b - }; - - _res; -}} - -pub define new(x ...args) -{ - x = alloc(sizeof(x)); - init(@ ...args); -} - -pub define ctx(x ...args) -{ - init(&x ...args); - defer(deinit(@)); -} - -main(argc i32, argv [argc] * u8) -{ - something = argv[10]; // run type bounds checking for ranged array? - // will not be automatically freed - new(a *string); - new(b *string, "hello"); - c string; // undefined state - // will be automatically 'freed' - ctx(c string); - ctx(v vec); - append(v, a); - append(v, c); -} diff --git a/examples/import.ct b/examples/import.ct deleted file mode 100644 index 36e7300..0000000 --- a/examples/import.ct +++ /dev/null @@ -1 +0,0 @@ -import vec.ct; diff --git a/examples/main.ct b/examples/main.ct deleted file mode 100644 index 4ebe8b7..0000000 --- a/examples/main.ct +++ /dev/null @@ -1,3 +0,0 @@ -main() i32 { - return 0; -} diff --git a/examples/numeral.ct b/examples/numeral.ct deleted file mode 100644 index 38936e9..0000000 --- a/examples/numeral.ct +++ /dev/null @@ -1,35 +0,0 @@ -/* good optimisation target: make these built in */ -type numeral { - u8; - u16; - u32; - u64; - i8; - i16; - i32; - i64; - isize; - usize; - float; - double; -} - -pub init(mut a *numeral) -{ - *a = 0; -} - -pub deinit(mut a *numeral) -{ - *a = 0; -} - -pub copy(mut a *numeral, b *numeral) -{ - *a = *b; -} - -pub move(mut a *numeral, mut b *numeral) -{ - *a = *b; -} diff --git a/examples/option.ct b/examples/option.ct deleted file mode 100644 index 483a9ee..0000000 --- a/examples/option.ct +++ /dev/null @@ -1,6 +0,0 @@ -type t {any}; - -struct option { - u8 res; - t val; -}; diff --git a/examples/res.ek b/examples/res.ek index f7c96df..a1854ae 100644 --- a/examples/res.ek +++ b/examples/res.ek @@ -1,6 +1,7 @@ /* simple example with C-like strings. A real implementation would likely want * to use a string wrapper or something. */ +typedef ptr {} typedef i27 {} typedef i9 {} diff --git a/examples/std.ct b/examples/std.ct deleted file mode 100644 index 339459f..0000000 --- a/examples/std.ct +++ /dev/null @@ -1,35 +0,0 @@ -type std { - init(mut * any); - deinit(mut * any); - copy(mut * any, * any); - move(mut * any, mut * any); -} - -/* these as well could be way optimized for builtin types */ -type comparable { - equal(* any, * any) bool; - less_than(* any, * any) bool; -} - -/* I'm imagining that if someone provides a specific function for these, it will - * be used rather than these ones, but that the minimum to implement comparable - * is as small as possible this should be fine */ -pub not_equal(a * comparable, b * comparable) bool -{ - return !equal(a, b); -} - -pub greater_than(a * comparable. b * comparable) bool -{ - return !equal(a, b) && !less_than(a, b); -} - -pub less_or_equal(a * comparable, b * comparable) bool -{ - return !greater_than(a, b); -} - -pub greater_or_equal(a * comparable, b * comparable) bool -{ - return !less_than(a, b); -} diff --git a/examples/std.ek b/examples/std.ek deleted file mode 100644 index fda6d23..0000000 --- a/examples/std.ek +++ /dev/null @@ -1,259 +0,0 @@ -/* comparison traits */ -pub define cmp[] { - eq(*cmp a, *cmp b => bool); - lt(*cmp a, *cmp b => bool); - bt(*cmp a, *cmp b => bool); - - ne(*cmp a, *cmp b => bool) {return !a.eq(b)} - - le(*cmp a, *cmp b => bool) {return !a.bt(b)} - ge(*cmp a, *cmp b => bool) {return !a.lt(b)} -} - -/* hash traits */ -pub define hash[] { - hash(*hash h => i27); -} - -/* builtin type 'implementations' */ -/* as a special case, builtin types are allowed to be typedef'd to implement - * interfaces */ -pub typedef i27 {} -pub typedef i9 { - fmt![]; - fmt(*i9 i, string args => result![string]) { - /* hmm, this static string would have to be deinitialized - * somewhere else with possibly bad results. Should free() or - * whatever I choose to use check if the pointer is in static - * memory or something? Or should it be the user's - * responsibility to ensure static strings are cloned? */ - return ok!(string!("123")); - } - - cmp![]; - eq(*i9 i, *i9 o => bool) { - return i* == o*; - } - - cmp(*i9 i, *i9 o => bool) { - return i* - o*; - } - - hash![]; - hash(*i9 i => i27) { - return i; - } -} - -pub typedef bool { -} - -/* special case of special case, 'str' means *i9 but pointers aren't allowed in - * the parser stage. Is this an ugly solution? Feels kind of ugly. */ -pub typedef str { - fmt![]; - fmt(*i9 s, string args => result![string]) { - /* here we should probably copy s in case it is statically - * defined */ - return ok!(string!("cp")); - } - - cmp![]; - eq(*i9 s, *i9 o => bool) { - if s == o {return true;} - /* iterate over stuff I guess */ - } - - lt(*i9 s, *i9 o => bool) { - if s == o {return false;} - /* iterate over stuff */ - } - - hash![]; - hash(*i9 s => i27) { - /* iterate over all characters and hash them I guess */ - } -} - -/* 'continue typedef' to implement more traits and stuff, can be postponed a bit - * as I don't think it's an essential feature yet. Might be in the future, - * though, just requires some extra finangling to figure out how each thing - * should work. - * Particularly template continuations might be a bit interesting, should we - * force the user to replicate the type arguments or should it be done - * automatically? - -pub continue str { - /* implement some other traits */ -}; -*/ - -/* any import */ -pub typedef any {} - -/* string import */ -pub typedef string { - usize len; - *i9 buf; -} - -pub define string(s) { - string!{.len = sizeof(s), .buf = s} -} - -/* result import */ -pub typedef result[any T] { - *i9 err; - T val; - - err(*result r => bool) { - return r*.err != null; - } -} - -pub define ok(v) { - result!{.err = null, .val = v}; -} - -pub define err(e) { - /* for this to work properly, I'll probably need some pretty decent type - * decuction...*/ - result!{.err = e}; -} - -pub define errv(e, v) { - result!{.err = e, .val = v}; -} - -/* fmt import */ -pub define fmt[] { - fmt(*fmt p, string args => result![string]); - str(*fmt p => string) { - /* is this a loop? allowed? */ - const r = p*.fmt(string!("")); - if r*.err() { - abort("error converting to string"); - } - - return r*.v; - } -} - -/* file import */ -pub typedef file { - /* file could also just be a memory region, kind of like memstream? */ -} - -/* here would be useful if macros could take type arguments as well, for example - * f must be a file and fmt must be a string, but I guess this is a quirk I can - * live with... */ -pub define fprint(f, fmt, ...args) { - /* possible name clash, hmmm */ - i27 __ek_reserved_pos = 0; - const for __ek_reserved_a : args { - __ek_reserved_pos += f.output_fmt_string(fmt, pos); - if __ek_reserved_pos < 0 { - abort("too many print arguments"); - } - - /* pos should be at a {}, with an unknown string of arguments - * within */ - /* find matching '}' */ - i27 __ek_reserved_prev_pos = __ek_reserved_pos; - do { - if fmt.at(__ek_reserved_pos) == '}' {break;} - __ek_reserved_pos += 1; - } while 1; - - /* skip leading '{' */ - __ek_reserved_prev_pos += 1; - - /* copy arguments to a separate string (probably pretty slow, a - * string_view or something could be beneficial here)*/ - const p = fmt.dup(__ek_reserved_prev_pos, __ek_reserved_pos); - const string r = a.fmt(p); - - /* better abort messages could be useful, provide some - * "stringify" operator? #a or something? I guess we have - * src_loc that could lift the appropriate code, maybe? not - * high priority for now anyway */ - if r.err() {abort("failed to format argument");} - f.output_raw_string(r.v); - - /* skip over trailing '}' */ - __ek_reserved_pos += 1; - } - - /* if output_fmt_string() still wants to continue, we have extra - * brackets that can't be handled as we ran out of args */ - if f.output_fmt_string(fmt, pos) > 0 { - abort("too few print arguments"); - } -} - -/* vec import */ -pub typedef vec[any T] { - // we want our vector to be formattable, used by print etc. - fmt![]; - fmt(*vec v, string args => result![string]) { - return ok!(string!("test")); - } - - usize len; - *T buf; - ^(usize) alloc; - - init(*vec v, ^(usize) alloc) { - v*.len = 0; - v*.buf = null; - v*.alloc = alloc; - } - - init(*vec v) { - v*.init(alloc); - } - - length(*vec v => usize) { return v.len; } - index(*vec v, usize i => T) - { - assert(i < v*.len, "index %zu out of bounds\n", i); - return &v*.buf[i]; - } - - index(*vec v, isize i => T) - { - if i < 0 { - assert(-i < v*.len, "reverse index %zi out of bounds\n", i); - return &v*.buf[v*.len + i]; - } - - /* v.whatever() is effectively syntactic sugar for - * whatever::typeof(v)(&v), but since I don't allow typeof() - * it's built-in. */ - return v*.index(i as usize); - } - - prepend(*vec v, T e) { v*.insert(e, 0); } - append(*vec v, T e) { v*.insert(e, v*.len); } - - preplace(*vec v, T e) { v*.place(e, 0); } - applace(*vec v, T e) { v*.place(e, v*.len); } - - place(*vec v, T e) {} - insert(*vec v, T e) {} - - deinit(*vec v) - { - for i27 i = 0; i < v.len; i += 1 { - deinit(v[i]); - v[i] = null; - } - - dealloc(v.buf); - } -} - -main() { - vec![i9] what; - what.length(); -} diff --git a/examples/v.ct b/examples/v.ct deleted file mode 100644 index 2026d55..0000000 --- a/examples/v.ct +++ /dev/null @@ -1,12 +0,0 @@ -main(argc u32, argv[argc] *u8) i32 -{ - ctx(vec(u32) a); - // equivalent to - ctx(struct (vec[u32]) a); - - // All entities defined with struct [vector] are seen as the same - // structure, i.e. mangled the same. Something like vector_u32 - // If someone adds a name, i.e. structure lol [vector(u32)] the mangling - // is lol_vector_u32 and considered a different type. All identical - // definitions of structs are considered the same struct, in short. -} diff --git a/examples/vec.ct b/examples/vec.ct deleted file mode 100644 index dee50ca..0000000 --- a/examples/vec.ct +++ /dev/null @@ -1,62 +0,0 @@ -type vectorable { - std; - /* this would be needed for comparisons like find() or something */ - comparable; -} - -type vec {t: vectorable} { - std_vector: void; - len: usize; - buf: 't; -} - -pub define vec(t) { struct (vec{t}) } - -pub init(v: 'vector) -{ - v.len = 0; - v.buf = null; -} - -pub length(v: *vec => usize) { return v.len; } - -pub index(v: *vec, i: usize => '#v.buf) -{ - assert(i < v.len, "index %zu out of bounds\n", i); - return &v.buf[i]; -} - -pub index(v: mut *vec, i: const isize => '#v.buf) -{ - if i < 0 { - assert(-i < v.len, "reverse index %zi out of bounds\n", i); - return &v.buf[v.len + i]; - } - - assert(i < v.len, "index %zi out of bounds\n", i); - return &v.buf[i]; -} - -pub prepend(v: mut 'vec, e: '#v.buf) { insert(v, e, 0); } -pub append(v: mut 'vec, e: '#v.buf) { insert(v, e, v.len); } - -pub preplace(v: mut 'vec, e: '#v.buf) { place(v, e, 0); } -pub applace(v: mut 'vec, e: '#v.buf) { place(v, e, v.len - 1); } - -pub place(v: mut *vec, e: '#v.buf, i: usize) -{ -} - -pub insert(v: mut *vec, e^ '#v.buf, i: usize) -{ -} - -pub deinit(mut v *vec) -{ - for i usize : v { - deinit(v[i]); - v[i] = null; - } - - dealloc(v.buf); -} -- cgit v1.3