diff options
| author | Kimplul <kimi.h.kuparinen@gmail.com> | 2024-02-16 00:20:18 +0200 |
|---|---|---|
| committer | Kimplul <kimi.h.kuparinen@gmail.com> | 2024-02-16 00:20:18 +0200 |
| commit | a83f6a2e53de7a9322755d68ebc9f13e3babecc2 (patch) | |
| tree | 599c2a5173f42d5a9b99e5cfdc1dcfe288bb2165 /examples | |
| parent | c85e4b4d2411e60af7387dec663ea62b03743eab (diff) | |
| download | ek-a83f6a2e53de7a9322755d68ebc9f13e3babecc2.tar.gz ek-a83f6a2e53de7a9322755d68ebc9f13e3babecc2.zip | |
rework
+ Kind of only a partial commit, but whatever, this history is pretty
ugly anyway
Diffstat (limited to 'examples')
| -rw-r--r-- | examples/std.ek | 243 |
1 files changed, 243 insertions, 0 deletions
diff --git a/examples/std.ek b/examples/std.ek new file mode 100644 index 0000000..4404730 --- /dev/null +++ b/examples/std.ek @@ -0,0 +1,243 @@ +/* comparison traits */ +pub typedef cmp { + eq(*cmp a, *cmp b => bool); + cmp(*cmp a, *cmp b => bool); + + ne(*cmp a, *cmp b => bool) {return !a.eq(b)} + + lt(*cmp a, *cmp b => bool) {return a.cmp(b) < 0} + bt(*cmp a, *cmp b => bool) {return a.cmp(b) > 0} + le(*cmp a, *cmp b => bool) {return !a.bt(b)} + ge(*cmp a, *cmp b => bool) {return !a.lt(b)} + +} + +/* hash traits */ +pub typedef 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 i9 { + fmt; + fmt(*i9 i, string args => result![string]) { + return ok!("123".str()); + } + + 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; + } +} + +/* 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 {.len = 2, .buf = "cp"} as string; + } + + 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; +} + +/* result import */ +pub typedef result[any T] { + *i9 err; + T val; + + err(*result r => bool) { + return r.err != null; + } +} + +pub define ok(v) { + {.err = null, .val = v} as result; +} + +pub define err(e) { + {.err = e} as result; +} + +/* fmt import */ +pub typedef fmt { + fmt(*fmt p, string args => result![string]); + str(*fmt p => string) { + /* is this a loop? allowed? */ + /* alternative would be {.len = 0, .buf = ""} as string I guess*/ + const r = p.fmt("".str()); + 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 quick 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!("test".str()); + } + + usize len; + *T buf; + ^(usize) alloc; + + init(*vec v, ^(usize) alloc) { + v.len = 0; + v.buf = null; + v.alloc = alloc; + } + + init(*vec v) { + init(v, 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 (usize i = 0); i < v.len; i += 1 { + deinit(v[i]); + v[i] = null; + } + + dealloc(v.buf); + } +} + +main() { + vec![i8] what; + what.length(); +} |
