aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorKimplul <kimi.h.kuparinen@gmail.com>2024-08-14 20:44:26 +0300
committerKimplul <kimi.h.kuparinen@gmail.com>2024-08-14 20:44:26 +0300
commit2023a7b2d9656f80b00de81453348c0a66f200f7 (patch)
tree06e4ea293318955cc4cf620428d04f1708c17364 /examples
parent1a56a881bc2c37614cfd074e7b986211c6d04809 (diff)
downloadek-2023a7b2d9656f80b00de81453348c0a66f200f7.tar.gz
ek-2023a7b2d9656f80b00de81453348c0a66f200f7.zip
test cleanup
+ Somewhat poor Git hygiene but I also fixed some bugs while I was at it.
Diffstat (limited to 'examples')
-rw-r--r--examples/alloc.ct18
-rw-r--r--examples/arc.ct53
-rw-r--r--examples/example.ct150
-rw-r--r--examples/import.ct1
-rw-r--r--examples/main.ct3
-rw-r--r--examples/numeral.ct35
-rw-r--r--examples/option.ct6
-rw-r--r--examples/res.ek1
-rw-r--r--examples/std.ct35
-rw-r--r--examples/std.ek259
-rw-r--r--examples/v.ct12
-rw-r--r--examples/vec.ct62
12 files changed, 1 insertions, 634 deletions
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<string>);
- 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 <t> {
- 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<u32>] 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);
-}