From bf580bb5580d48e6c2a59ffe094f0edc391d7690 Mon Sep 17 00:00:00 2001 From: JJ Date: Sat, 30 Dec 2023 17:41:19 -0800 Subject: std: initial draft of strings and lists --- std/pointers.pk | 3 ++ std/prelude/lists.pk | 109 +++++++++++++++++++++++++++++++++++++++++++++++++ std/prelude/strings.pk | 100 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 212 insertions(+) create mode 100644 std/pointers.pk create mode 100644 std/prelude/lists.pk create mode 100644 std/prelude/strings.pk (limited to 'std') diff --git a/std/pointers.pk b/std/pointers.pk new file mode 100644 index 0000000..1856ab1 --- /dev/null +++ b/std/pointers.pk @@ -0,0 +1,3 @@ +## std.pointers: Pointer arithmetic. Unsafe. + +# idk what goes here diff --git a/std/prelude/lists.pk b/std/prelude/lists.pk new file mode 100644 index 0000000..410cfed --- /dev/null +++ b/std/prelude/lists.pk @@ -0,0 +1,109 @@ +## std.lists: Dynamic arrays. +## This module is imported by default. +# reference: https://doc.rust-lang.org/nomicon/vec/vec.html + +use std.pointers + +## The list type. +type list[T] = struct + data: unique[T] # hrm + capacity: int + length: int + +## Initialize and return an empty list with inner type T. +pub func init[T](): list[T] = + ... # malloc? idk + let (data, ) + { data: , capacity: 0, length: 0 } + +## Gets the length of a list. +pub func len[T](self: list[T]): uint = + self.length + +pub func empty[T](self: list[T]): bool = + self.length == 0 + +## Gets the internal capacity of a list. +func cap[T](self: list[T]): uint = + self.capacity + +## Expands the capacity of a list. +func grow[T](self: mut list[T]) = + ... + +## Pushes a new element to the end of a list. +pub func push[T](self: mut list[T], val: owned T) = + if self.length == self.capacity: + self.grow() + unsafe: # todo: do we want unsafe blocks, as they are in rust? + self.data.raw_set(self.length, val) # fixme + # unsafe { ptr::write(self.ptr().add(self.length), val); } + self.length += 1 + +## Takes ownership of and pushes all the values of a list into another list. +pub func push[T](self: mut list[T], val: owned list[T]) = + ... + +## Removes & returns an element from the end of a list, if it exists. +pub func pop[T](self: mut list[T]): T? = + if self.length == 0: + None + unsafe: + self.length -= 1 + Some(self.data.raw_get[T](self.length)) # fixme + # unsafe { Some(ptr::read(self.ptr().add(self.length))) } + +## Returns a reference to an element of a list, if in range. +pub func get[T](self: list[T], i: uint): lent T? = + ... + +## Sets the element of a list to a value. todo: when is `val` owned? +## todo: how do we deal with having the wrong offset? +pub func set[T](self: mut list[T], i: uint, val: owned T) = + ... + +## Inserts a value at a location and shifts elements of the list accordingly. +pub func insert[T](self: mut list[T], i: uint, val: T) = + assert i <= self.length, "index out of bounds" + if self.cap == self.len: + self.grow() + ... + # unsafe { + # ptr::copy( + # self.ptr().add(index), + # self.ptr().add(index + 1), + # self.len - index, + # ); + # ptr::write(self.ptr().add(index), elem); + # self.len += 1; + # } + +## Removes a value at a location and shifts elements of the list accordingly. +pub func remove[T](self: mut list[T], i: uint): T = + assert index < self.length, "index out of bounds" + unsafe: + self.length -= 1 + result = ... + # unsafe { + # self.len -= 1; + # let result = ptr::read(self.ptr().add(index)); + # ptr::copy( + # self.ptr().add(index + 1), + # self.ptr().add(index), + # self.len - index, + # ); + # result + # } + +## Gets the last element of a list, if it exists. +pub func last[T](self: list[T]): lent T? = + self.get(self.len - 1) + +# todo: iteration... +# todo: destructors... +# todo: syntax for inlining + other pragmas... as a macro, perhaps? +# todo: slices + +type slice[T] = struct + data: ptr[T] # hrm... + length: uint diff --git a/std/prelude/strings.pk b/std/prelude/strings.pk new file mode 100644 index 0000000..c2b0518 --- /dev/null +++ b/std/prelude/strings.pk @@ -0,0 +1,100 @@ +## std.strings: The standard implementation of strings. +## This module is imported by default. +# reference: https://doc.rust-lang.org/std/string/struct.String.html + +use std.pointers + +# possible approaches: list[byte], distinct list[byte], this +# should *really* just rely on lists, i don't want to duplicate slicing logic, but... maybe... +type str = struct + data: ptr[byte] + length: uint + capacity: uint + +## Initialize and return an empty string. +pub func init(): str = + ... + +## Gets the length of a string. +pub func len(self: str): uint = + self.length + +pub func empty(self: str): bool = + self.length == 0 + +## Gets the internal capacity of a string. +func cap(self: str): uint = + self.capacity + +## Expands the capacity of a string. +func grow(self: mut str) = + ... + +## Pushes a character to the end of a mutable string. +pub func push(self: mut str, val: chr) = # todo: `add` alias? + ... + +## Pushes an owned string to the end of a mutable string. +pub func push(self: mut str, val: str) = + ... + +## Removes and returns the last character of a string, if it exists. +pub func pop(self: mut str): chr? = + ... + +## Returns the character at the provided index, if it exists. +pub func get(self: str, i: uint): chr? = + ... + +## Sets the character at the provided index, if it exists. +## todo: what if it does not exist? +pub func set(self: mut str, i: uint, val: chr) = + ... + +## Inserts a character at an arbitrary position within a string. +## Error handling: todo +pub func insert(self: mut str, i: uint, val: chr) = + ... + +## Removes and returns a character at an arbitrary position within a string. +## Panics on failure. +pub func remove(self: mut str, i: uint): chr = + ... + +## Returns the *byte* at an arbitrary position within a string. +## Explicitly distinct from `get` as this breaks safety conventions idk +pub func get_byte(self: str): byte = + ... + +## Sets a byte at the provided index, if it exists. Do we want this? +pub func set_byte(self: mut str, i: uint, val: byte) = + ... + +## Inserts a byte into a string. Breaks string convention. Do we want this? +pub func insert_byte(self: mut str, i: uint, val: byte) = + ... + +## Removes a byte at a given offset from a string. Do we want this? +pub func remove_byte(self: mut str, i: uint): byte? = + ... + +## Converts a given string to a list of bytes for iteration purposes. +pub func bytes(self: str): list[byte] = + ... # many performance considerations + +## Converts a given string to a list of chars for iteration purposes. +pub func chars(self: str): list[chr] # todo: useful? + +## The concatenation operator. +pub func &(a: str, b: str): str = + ... + +## Syntatic sugar for sring appending. +pub func &=(a: mut str, b: owned str) = + a.push(b) + +# todo: many things + +# pub func iter(self: str): StrIter +# pub func next(self: mut StrIter) +# pub func peek(self: mut StrIter) -- cgit v1.2.3-70-g09d2