diff options
| author | Kai Gunger <kgunger12@gmail.com> | 2026-07-11 16:17:57 -0400 |
|---|---|---|
| committer | Kai Gunger <kgunger12@gmail.com> | 2026-07-11 16:17:57 -0400 |
| commit | f56c11b48ac6ef65622d38da2d8d8ff04dd4049d (patch) | |
| tree | c599c9c2986f240187c403cf4eb2ffed0d1678f4 | |
| parent | fd5d79d8a2e438fac351099553438ed071d63d84 (diff) | |
| -rw-r--r-- | algo/algo.tnsl | 4 | ||||
| -rw-r--r-- | box/box.tnsl | 5 | ||||
| -rw-r--r-- | box/list.tnsl | 149 | ||||
| -rw-r--r-- | internal/c_wrap_linux.tnsl | 272 | ||||
| -rw-r--r-- | internal/c_wrap_windows.tnsl | 284 | ||||
| -rw-r--r-- | io/file.tnsl | 116 | ||||
| -rw-r--r-- | io/io.tnsl | 5 | ||||
| -rw-r--r-- | io/path.tnsl | 50 | ||||
| -rw-r--r-- | lang/lang.tnsl | 4 | ||||
| -rw-r--r-- | libtnsl.tnsl | 13 | ||||
| -rw-r--r-- | text/cstr.tnsl | 31 | ||||
| -rw-r--r-- | text/text.tnsl | 5 |
12 files changed, 938 insertions, 0 deletions
diff --git a/algo/algo.tnsl b/algo/algo.tnsl new file mode 100644 index 0000000..7c261ae --- /dev/null +++ b/algo/algo.tnsl @@ -0,0 +1,4 @@ + +/; module algo +;/ + diff --git a/box/box.tnsl b/box/box.tnsl new file mode 100644 index 0000000..189392f --- /dev/null +++ b/box/box.tnsl @@ -0,0 +1,5 @@ + +/; module box + import "list.tnsl" +;/ + diff --git a/box/list.tnsl b/box/list.tnsl new file mode 100644 index 0000000..58278e4 --- /dev/null +++ b/box/list.tnsl @@ -0,0 +1,149 @@ + +# List type - array backed list of elements +struct List { + ~void data, + + uint + count, + size, + _elsz +} + +uint VECTOR_MIN_ELEMENTS = 4 +uint VECTOR_MAX_GROW = 256 + +/; method Vector + + /; init (uint elsz) + self._elsz = elsz + self.size = VECTOR_MIN_ELEMENTS + self.count = 0 + self.data = _alloc(self.size * self._elsz) + ;/ + + /; from_cstr(~uint8 cstr) + self.init(1) + self.push_cstr(cstr) + ;/ + + /; _grow (uint i) + self.size = self.size + i + self.data = _realloc(self.data, self.size * self._elsz) + ;/ + + /; get (uint index) [~void] + /; if (index !< self.count) + return NULL + ;/ + + return self.data + index * self._elsz + ;/ + + /; push (~void el) + /; if (self.size == self.count + 1) + /; if (self.size < VECTOR_MAX_GROW) + self._grow(self.size) + ;; else + self._grow(VECTOR_MAX_GROW) + ;/ + ;/ + + ~void start = self.data + self.count * self._elsz + /; loop (int i = 0; i < self._elsz) [i++] + ~uint8 to = start + i + ~uint8 from = el + i + to` = from` + ;/ + self.count++ + ;/ + + /; replace (int index, ~void el) + ~uint8 start = self.get(index) + /; if (start == NULL) + return + ;/ + + /; loop (int i = 0; i < self._elsz) [i++] + ~uint8 to = start + i + ~uint8 from = el + i + to` = from` + ;/ + ;/ + + /; _shrink(uint i) + /; if (i !< self.size) + self.size = 1 + ;; else + self.size = self.size - i + ;/ + + self.data = _realloc(self.data, self.size * self._elsz) + ;/ + + /; pop + self.remove(self.count - 1) + ;/ + + /; remove (int index) + /; if (index < 0 || index !< self.count) + return + ;/ + + /; if (self.count > 1) + /; loop (int i = index * self._elsz; i < (self.count - 1) * self._elsz) [i++] + ~uint8 to = self.data + i + ~uint8 from = self.data + i + self._elsz + to` = from` + ;/ + ;/ + + self.count-- + + /; if (self.count < self.size / 2) + self._shrink(self.size / 3) + ;/ + ;/ + + /; push_char (uint8 ch) + self.push(~ch) + ;/ + + /; push_cstr(~uint8 ch) + /; loop (ch` !== 0) [ch++] + self.push(ch) + ;/ + ;/ + + /; as_cstr [~uint8] + ~uint8 z = self.data + self.count + z` = 0 + return self.data + ;/ + + /; end + self.count = 0 + self.size = 0 + self._elsz = 0 + _delete(self.data) + ;/ + + /; copy [Vector] + Vector out + + out.init(self._elsz) + /; loop (int i = 0; i < self.count) [i++] + ~int tmp = self.get(i) + out.push(tmp) + ;/ + + return out + ;/ + + /; back [~void] + /; if (self.count > 0) + return self.get(self.count - 1) + ;/ + return NULL + ;/ +;/ + diff --git a/internal/c_wrap_linux.tnsl b/internal/c_wrap_linux.tnsl new file mode 100644 index 0000000..31bee1a --- /dev/null +++ b/internal/c_wrap_linux.tnsl @@ -0,0 +1,272 @@ +# Must be included at the top of the file +asm "extern malloc, realloc, free, printf, putchar, open, close, read, write, lseek, perror" + +~void NULL = 0 + +/; _alloc (uint size) [~void] + ~void out + + asm "mov rax, rsp" + asm "xor rdx, rdx" + asm "mov rcx, 16" + asm "div rcx" + asm "sub rsp, rdx" + asm "sub rsp, 128" + + # Mov size into proper register, and set all extras to zero + asm "mov rdi, r10" + asm "mov rsi, 0" + asm "xor rax, rax" + + # Do call + asm "call malloc wrt ..plt" + + # Set out to the returned value + # (The compiler assignes spaces sequentially, and we have a uint in r10) + asm "mov r11, rax" + + return out +;/ + +/; _realloc (~void ptr, uint new_size) [~void] + ~void out + + asm "mov rax, rsp" + asm "xor rdx, rdx" + asm "mov rcx, 16" + asm "div rcx" + asm "sub rsp, rdx" + asm "sub rsp, 128" + + # Mov ptr and new size into proper registers, and set all extras to zero + asm "mov rdi, r10" + asm "mov rsi, r11" + asm "xor rax, rax" + + # Do call + asm "call realloc wrt ..plt" + + # Set out to the returned value + # (The compiler assignes spaces sequentially. We have a ptr in r10, and a uint in r11) + asm "mov r12, rax" + + return out +;/ + +/; _delete (~void ptr) + + asm "mov rax, rsp" + asm "xor rdx, rdx" + asm "mov rcx, 16" + asm "div rcx" + asm "sub rsp, rdx" + asm "sub rsp, 128" + + # setup call by clearing most values + asm "mov rdi, r10" + asm "mov rsi, 0" + asm "xor rax, rax" + + # do call + asm "call free wrt ..plt" + + # there's no more to do 'cause free returns nothing +;/ + +/; _putchar (uint8 char) + + asm "mov rax, rsp" + asm "xor rdx, rdx" + asm "mov rcx, 16" + asm "div rcx" + asm "sub rsp, rdx" + asm "sub rsp, 128" + + # setup call by clearing most values + asm "mov rdi, r10" + asm "xor rsi, rsi" + asm "xor rax, rax" + + # do call + asm "call putchar wrt ..plt" + + # there's no more to do 'cause I don't care about putchar's output +;/ + +# wrap around putchar ( I was dumb and was using printf when I shouldn't have been ) +/; _print (~uint8 str) + /; loop (str` !== 0) [str++] + _putchar(str`) + ;/ +;/ + +/; _print_num (~void str, int num) + + asm "mov rax, rsp" + asm "xor rdx, rdx" + asm "mov rcx, 16" + asm "div rcx" + asm "sub rsp, rdx" + asm "sub rsp, 128" + + # setup call by clearing most values + asm "mov rdi, r10" + asm "mov rsi, r11" + asm "xor rax, rax" + + # do call + asm "call printf wrt ..plt" + + # there's no more to do 'cause printf returns nothing +;/ + + +# Create file for writing (overwrite) +/; _create_file (~void name) [int] + int out + + asm "mov rax, rsp" + asm "xor rdx, rdx" + asm "mov rcx, 16" + asm "div rcx" + asm "sub rsp, rdx" + asm "sub rsp, 128" + + # Do call + asm "mov rdi, r10" + asm "mov rsi, 0q1102" + asm "mov rdx, 0q700" + asm "call open wrt ..plt" + + # Set out to the returned value + # (The compiler assignes spaces sequentially. We have a ptr in r8) + asm "mov r11, rax" + + return out +;/ + +# Open file for reading or writing (no overwrite) +/; _open_file (~void name) [int] + int out + + asm "mov rax, rsp" + asm "xor rdx, rdx" + asm "mov rcx, 16" + asm "div rcx" + asm "sub rsp, rdx" + asm "sub rsp, 128" + + # Do syscall + asm "mov rdi, r10" + asm "mov rsi, 2" + asm "mov rdx, 0q700" + asm "call open wrt ..plt" + + # Set out to the returned value + # (The compiler assignes spaces sequentially. We have a ptr in r8, and a uint in r9) + asm "mov r11, rax" + + return out +;/ + +/; _close_file (int handle) + + asm "mov rax, rsp" + asm "xor rdx, rdx" + asm "mov rcx, 16" + asm "div rcx" + asm "sub rsp, rdx" + asm "sub rsp, 128" + + # Do syscall + asm "mov rdi, r10" + asm "call close wrt ..plt" +;/ + +/; _read_byte (int handle, ~uint8 byte) [int] + int out + + asm "mov rax, rsp" + asm "xor rdx, rdx" + asm "mov rcx, 16" + asm "div rcx" + asm "sub rsp, rdx" + asm "sub rsp, 128" + + # Do syscall + asm "mov rdi, r10" # handle + asm "mov rsi, r11" # buffer + asm "mov rdx, 1" # one byte + asm "call read wrt ..plt" + + # return number of bytes read + asm "mov r12, rax" + + return out +;/ + +/; _fseek (int handle, uint pos) [int] + int out + + # align stack + asm "mov rax, rsp" + asm "xor rdx, rdx" + asm "mov rcx, 16" + asm "div rcx" + asm "sub rsp, rdx" + # add buffer zone to stack + asm "sub rsp, 128" + + # Call c func + asm "mov rdi, r10" + asm "mov rsi, r11" + asm "mov rdx, 0" # standard value for SEEK_SET as per GNU libc + asm "call lseek wrt ..plt" + + # get return value + asm "mov r12, rax" + + return out +;/ + +/; _write_byte (int handle, ~uint8 byte) [int] + int out + + asm "mov rax, rsp" + asm "xor rdx, rdx" + asm "mov rcx, 16" + asm "div rcx" + asm "sub rsp, rdx" + asm "sub rsp, 128" + + # Do syscall + asm "mov rdi, r10" # handle + asm "mov rsi, r11" # buffer + asm "mov rdx, 1" # one byte + asm "call write wrt ..plt" + + asm "mov r12, rax" + + return out +;/ + +/; _perror (~void str) + + asm "mov rax, rsp" + asm "xor rdx, rdx" + asm "mov rcx, 16" + asm "div rcx" + asm "sub rsp, rdx" + asm "sub rsp, 128" + + # setup call by clearing most values + asm "mov rdi, r10" + asm "xor rsi, rsi" + asm "xor rax, rax" + + # do call + asm "call perror wrt ..plt" + + # there's no more to do 'cause printf returns nothing +;/ + diff --git a/internal/c_wrap_windows.tnsl b/internal/c_wrap_windows.tnsl new file mode 100644 index 0000000..839c976 --- /dev/null +++ b/internal/c_wrap_windows.tnsl @@ -0,0 +1,284 @@ +# Must be included at the top of the file +asm "extern malloc" +asm "extern realloc" +asm "extern free" + +asm "extern printf" + +asm "extern CreateFileA" +asm "extern ReadFile" +asm "extern WriteFile" +asm "extern CloseHandle" + +~uint8 _alert = "Alert!\n\0" +~uint8 _dec = "%d\n\0" +~uint8 _ptr = "%p\n\0" + +/; _alloc (uint size) [~void] + ~void out + + asm "mov rax, rsp" + asm "xor rdx, rdx" + asm "mov rcx, 32" + asm "div rcx" + asm "sub rsp, rdx" + asm "sub rsp, 32" + + # Mov size into proper register, and set all extras to zero + asm "mov rcx, r8" + asm "mov rdx, 0" + asm "mov r8, 0" + asm "mov r9, 0" + + asm "call malloc" + # Set out to the returned value + # (The compiler assignes spaces sequentially, and we have a uint in r8) + asm "mov r9, rax" + return out +;/ + +/; _realloc (~void ptr, uint new_size) [~void] + ~void out + + asm "mov rax, rsp" + asm "xor rdx, rdx" + asm "mov rcx, 32" + asm "div rcx" + asm "sub rsp, rdx" + asm "sub rsp, 32" + + # Mov ptr and new size into proper registers, and set all extras to zero + asm "mov rcx, r8" + asm "mov rdx, r9" + asm "mov r8, 0" + asm "mov r9, 0" + # Do call + asm "call realloc" + # Set out to the returned value + # (The compiler assignes spaces sequentially. We have a ptr in r8, and a uint in r9) + asm "mov r10, rax" + return out +;/ + +/; _delete (~void ptr) + + asm "mov rax, rsp" + asm "xor rdx, rdx" + asm "mov rcx, 32" + asm "div rcx" + asm "sub rsp, rdx" + asm "sub rsp, 32" + + # setup call by clearing most values + asm "mov rcx, r8" + asm "mov rdx, 0" + asm "mov r8, 0" + asm "mov r9, 0" + # do call + asm "call free" + # there's no more to do 'cause free returns nothing +;/ + +/; _printf (~void str) + + asm "mov rax, rsp" + asm "xor rdx, rdx" + asm "mov rcx, 32" + asm "div rcx" + asm "sub rsp, rdx" + asm "push qword 0" + asm "push qword 0" + asm "push qword 0" + asm "push qword 0" + + # setup call by clearing most values + asm "mov rcx, r8" + asm "mov rdx, 0" + asm "mov r8, 0" + asm "mov r9, 0" + # do call + asm "call printf" + # there's no more to do 'cause printf returns nothing +;/ + +/; _print_num (~void str, int num) + + asm "mov rax, rsp" + asm "xor rdx, rdx" + asm "mov rcx, 32" + asm "div rcx" + asm "sub rsp, rdx" + asm "push qword 0" + asm "push qword 0" + asm "push qword 0" + asm "push qword 0" + + # setup call by clearing most values + asm "mov rcx, r8" + asm "mov rdx, r9" + asm "mov rdi, 0" + asm "mov rsi, 0" + asm "mov r8, 0" + asm "mov r9, 0" + # do call + asm "call printf" + # there's no more to do 'cause printf returns nothing +;/ + + +# Create file for writing (overwrite) +/; _create_file (~void name) [~void] + ~void out + + asm "mov rax, rsp" + asm "xor rdx, rdx" + asm "mov rcx, 32" + asm "div rcx" + asm "sub rsp, rdx" + + asm "mov rcx, r8" # lpFileName + asm "mov rdx, 1" # dwDesiredAccess + asm "shl rdx, 28" # (GENERIC_READ 1 << 31 | GENERIC_WRITE 1 << 30) + asm "mov r8, 3" # dwShareMode + asm "mov r9, 0" # lpSecurityAttributes + + asm "push qword 0" # hTemplateFile + asm "push qword 128" # dwFlagsAndAttributes (NORMAL_FILE = 128) + asm "push qword 2" # dwCreationDisposition (CREATE_ALWAYS = 2) + + # Shadow space + asm "push r9" + asm "push r8" + asm "push rdx" + asm "push rcx" + + # Do call + asm "call CreateFileA" + + # Set out to the returned value + # (The compiler assignes spaces sequentially. We have a ptr in r8) + asm "mov r9, rax" + + return out +;/ + +# Open file for reading or writing (no overwrite) +/; _open_file (~void name) [~void] + ~void out + + asm "mov rax, rsp" + asm "xor rdx, rdx" + asm "mov rcx, 32" + asm "div rcx" + asm "sub rsp, rdx" + + asm "mov rcx, r8" # lpFileName + asm "mov rdx, 1" # dwDesiredAccess + asm "shl rdx, 28" # (GENERIC_READ 1 << 31 | GENERIC_WRITE 1 << 30) + asm "mov r8, 3" # dwShareMode + asm "mov r9, 0" # lpSecurityAttributes + + asm "push qword 0" # hTemplateFile + asm "push qword 128" # dwFlagsAndAttributes (NORMAL_FILE = 128) + asm "push qword 3" # dwCreationDisposition (OPEN_EXISTING = 3) + + # Shadow space + asm "push r9" + asm "push r8" + asm "push rdx" + asm "push rcx" + + # Do call + asm "call CreateFileA" + + # Set out to the returned value + # (The compiler assignes spaces sequentially. We have a ptr in r8, and a uint in r9) + asm "mov r9, rax" + + return out +;/ + +/; _close_file (~void handle) + + asm "mov rax, rsp" + asm "xor rdx, rdx" + asm "mov rcx, 32" + asm "div rcx" + asm "sub rsp, rdx" + + asm "mov rcx, r8" # handle + asm "mov rdx, 0" + asm "mov r8, 0" + asm "mov r9, 0" + + # Shadow space + asm "push r9" + asm "push r8" + asm "push rdx" + asm "push rcx" + + asm "call CloseHandle" + + asm "add rsp, 32" +;/ + +/; _read_byte (~void handle, ~uint8 byte) [int] + ~int out + int i = 0 + out = ~i + + + asm "mov rax, rsp" + asm "xor rdx, rdx" + asm "mov rcx, 32" + asm "div rcx" + asm "sub rsp, rdx" + + asm "mov rcx, r8" # handle + asm "mov rdx, r9" # buffer + asm "mov r8, 1" # one byte + asm "mov r9, r10" # read bytes buffer + asm "push qword 0" + + # Shadow space + asm "push r9" + asm "push r8" + asm "push rdx" + asm "push rcx" + + asm "call ReadFile" + + return out` +;/ + +/; _write_byte (~void handle, ~uint8 byte) [int] + ~int out + int i = 0 + out = ~i + + asm "mov rax, rsp" + asm "xor rdx, rdx" + asm "mov rcx, 32" + asm "div rcx" + asm "sub rsp, rdx" + + asm "mov rcx, r8" # handle + asm "mov rdx, r9" # buffer + asm "mov r8, 1" # one byte + asm "mov r9, 0" + asm "push qword 0" + + # Shadow space + asm "push r9" + asm "push r8" + asm "push rdx" + asm "push rcx" + + asm "call WriteFile" + + return out` +;/ + +/; print_alert + _printf(_alert) +;/ diff --git a/io/file.tnsl b/io/file.tnsl new file mode 100644 index 0000000..2786179 --- /dev/null +++ b/io/file.tnsl @@ -0,0 +1,116 @@ + +# File type +struct File { + # List containing the path + Path path, + int32 handle, + uint pos, + bool at_end +} + +/; method File + /; init (~uint8 str) + self.path.init() + self.path.from_cstr(str) + self.handle = 0 + self.handle-- + self.at_end = false + self.pos = 0 + ;/ + + /; relative (~uint8 path) [File] + Path rel = self.path.relative(path) + ~uint8 new_path = rel.to_cstr() + File out + out.init(new_path) + _delete(new_path) + rel.end() + return out + ;/ + + /; end + /; if (self.handle + 1 !== 0) + _close_file(self.handle) + self.handle = 0 + self.handle-- + ;/ + self.path.end() + ;/ + + /; open + ~uint8 p = self.path.to_cstr() + self.handle = _open_file(p) + + /; if (self.handle + 1 == 0) + self.at_end = true + ;/ + _delete(p) + ;/ + + /; create + ~uint8 p = self.path.to_cstr() + self.handle = _create_file(p) + /; if (self.handle + 1 == 0) + self.at_end = true + ;/ + _delete(p) + ;/ + + /; close + /; if (self.handle + 1 !== 0) + _close_file(self.handle) + self.handle = 0 + self.handle-- + self.at_end = false + ;/ + ;/ + + /; read [uint8] + /; if (self.at_end == true) + return 0 + ;/ + + uint8 out + int bytes = _read_byte(self.handle, ~out) + self.pos = self.pos + 1 + + /; if (bytes == 0) + self.at_end = true + return 0 + ;; else if (bytes !== 1) + _perror("Error reading from file\0") + _print_num("FD: %ld\n\0", self.handle) + self.at_end = true + return 0 + ;/ + + return out + ;/ + + /; unread + /; if (self.pos < 1) + return + ;/ + + self.pos = self.pos - 1 + _fseek(self.handle, self.pos) + + /; if (self.at_end == true) + self.at_end = false + ;/ + ;/ + + /; write (uint8 byte) + int written = _write_byte(self.handle, ~byte) + /; if (written == 0) + self.at_end = true + ;/ + ;/ + + /; write_cstr (~uint8 str) + /; loop (self.at_end == false && str` !== 0) [str++] + self.write(str`) + ;/ + ;/ + +;/ diff --git a/io/io.tnsl b/io/io.tnsl new file mode 100644 index 0000000..5baead5 --- /dev/null +++ b/io/io.tnsl @@ -0,0 +1,5 @@ + +/; module io + import "file.tnsl" +;/ + diff --git a/io/path.tnsl b/io/path.tnsl new file mode 100644 index 0000000..f72397d --- /dev/null +++ b/io/path.tnsl @@ -0,0 +1,50 @@ + +# Path type +struct Path { + box.List strings +} + +uint8 PATH_SEP = '/' +~uint8 PARENT_DIR = "..\0" +~uint8 CURRENT_DIR = ".\0" + +/; method Path + /; init + self.strings.init(8) + ;/ + + /; from_cstr (~uint8 path) + ;/ + + /; to_cstr [~uint8] + box.List out + out.from_cstr("\0") + + /; if (self.strings.count < 1) + return out.as_cstr() + ;/ + + ~uint8 str = self.strings.get(0) + out.push_cstr(str) + + /; loop (int i = 1; i < self.strings.count) [i++] + out.push(~PATH_SEP) + out.push_cstr(str) + ;/ + + return out.as_cstr() + ;/ + + /; relative (~uint8 path) [Path] + + ;/ + + /; end + ~~uint8 str + /; loop (int i = 0; i < self.strings.count) [i++] + str = self.strings.get(i) + _delete(str`) + ;/ + self.strings.end() + ;/ +;/ diff --git a/lang/lang.tnsl b/lang/lang.tnsl new file mode 100644 index 0000000..b9cc157 --- /dev/null +++ b/lang/lang.tnsl @@ -0,0 +1,4 @@ + +/; module lang +;/ + diff --git a/libtnsl.tnsl b/libtnsl.tnsl index e69de29..dcad398 100644 --- a/libtnsl.tnsl +++ b/libtnsl.tnsl @@ -0,0 +1,13 @@ +# Base module for libtnsl +/; module tnsl + # Wrap c calls for now wrt memory management + import "internal/c_wrap_linux.tnsl" + + # Basic modules + import "algo/algo.tnsl" + import "box/box.tnsl" + import "io/io.tnsl" + import "lang/lang.tnsl" + import "text/text.tnsl" +;/ + diff --git a/text/cstr.tnsl b/text/cstr.tnsl new file mode 100644 index 0000000..67db577 --- /dev/null +++ b/text/cstr.tnsl @@ -0,0 +1,31 @@ + +/; cstr_cmp (~uint8 a, b) [bool] + /; loop (a` == b` && a` !== 0 && b` !== 0) [a++; b++] ;/ + + /; if (b` == 0 && a == 0) + return true + ;/ + + return false +;/ + +/; cstr_len (~uint8 a) [uint] + uint out = 0 + /; loop (str` !== 0) [str++; out++] ;/ + return out +;/ + +/; cstr_starts_with (~uint8 str, prefix) [bool] + int chk = cstr_len(suffix) + int counter = 0 + + /; loop (str` !== 0) [str++] + ;/ + +/; cstr_ends_with (~uint8 str, suffix) [bool] + int chk = cstr_len(suffix) + int counter = 0 + + /; loop (str` !== 0) [str++] + ;/ +;/ diff --git a/text/text.tnsl b/text/text.tnsl new file mode 100644 index 0000000..951e697 --- /dev/null +++ b/text/text.tnsl @@ -0,0 +1,5 @@ + +/; module text + import "cstr.tnsl" +;/ + |