From 4081b63885dc936e9f376f836f3b231caabd98d3 Mon Sep 17 00:00:00 2001 From: Igor Parfenov Date: Mon, 30 Dec 2024 18:44:32 +0300 Subject: [PATCH] Altlib Reference --- README.md | 4 +- altlib/Makefile | 12 +- altlib/algorithm.al | 6 + altlib/cassert.al | 4 + altlib/generate_docs.c | 131 +++++++++ altlib/header.html | 70 +++++ altlib/memory.al | 7 + altlib/posix.al | 3 + altlib/stdio.al | 33 +++ altlib/stdlib.al | 3 + altlib/string.al | 2 + altlib/test_allocator.al | 3 + altlib/vector.al | 3 + docs/altlibref.html | 558 +++++++++++++++++++++++++++++++++++++++ 14 files changed, 837 insertions(+), 2 deletions(-) create mode 100644 altlib/generate_docs.c create mode 100644 altlib/header.html create mode 100644 docs/altlibref.html diff --git a/README.md b/README.md index 443db64..652f4ee 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,9 @@ A system programming language ## Documentation -[Language Reference](https://htmlpreview.github.io/?https://github.com/ParfenovIgor/alias-c/blob/main/docs/langref.html) +[Alias Language Reference](https://htmlpreview.github.io/?https://github.com/ParfenovIgor/alias-c/blob/main/docs/langref.html) + +[Altlib Reference](https://htmlpreview.github.io/?https://github.com/ParfenovIgor/alias-c/blob/main/docs/altlibref.html) ## Installation diff --git a/altlib/Makefile b/altlib/Makefile index f69bde1..d53a2c1 100644 --- a/altlib/Makefile +++ b/altlib/Makefile @@ -1,13 +1,23 @@ ALFLAGS=-i altlib ./ +CFLAGS=-I ../stdlib/include SRCS_AL := $(wildcard *.al) OBJS_AL := $(patsubst %.al, $(BUILD_DIR)/altlib/%.o, $(SRCS_AL)) -all: $(OBJS_AL) +OBJS_STDLIB := $(wildcard $(BUILD_DIR)/stdlib/*.o) + +all: $(OBJS_AL) docs $(BUILD_DIR)/altlib/%.o: %.al make_dir $(BUILD_DIR)/calias -a $(ALFLAGS) $< -o $@ +$(BUILD_DIR)/altlib/generate_docs: generate_docs.c + gcc $(CFLAGS) $< $(OBJS_STDLIB) -o $@ + +docs: $(BUILD_DIR)/altlib/generate_docs + cat header.html > ../docs/altlibref.html + $< $(SRCS_AL) >> ../docs/altlibref.html + make_dir: mkdir -p $(BUILD_DIR)/altlib diff --git a/altlib/algorithm.al b/altlib/algorithm.al index 78c0a72..2e5a8c7 100644 --- a/altlib/algorithm.al +++ b/altlib/algorithm.al @@ -1,5 +1,11 @@ +//* algorithm + +//* min_ +//* Gets two integer values and returns the minimum one. func ^.min_(a #I, b #I) -> #I if (a < b) a else b +//* max_ +//* Gets two integer values and returns the maximum one. func ^.max_(a #I, b #I) -> #I if (a < b) b else a diff --git a/altlib/cassert.al b/altlib/cassert.al index 8321ea2..a39d0be 100644 --- a/altlib/cassert.al +++ b/altlib/cassert.al @@ -1,5 +1,9 @@ include altlib."posix.al" +//* cassert + +//* assert_ +//* Gets one integer value and stop execution with return code `3`, if the value is `0`. func ^.assert_(x #I) -> #V { eval if (not x) { eval posix_exit(3) } } diff --git a/altlib/generate_docs.c b/altlib/generate_docs.c new file mode 100644 index 0000000..f5f6297 --- /dev/null +++ b/altlib/generate_docs.c @@ -0,0 +1,131 @@ +#include +#include +#include +#include + +const char *sections[1024]; +const char *subsections[1024][1024]; + +void parse(int section_id, char *filename, int fd) { + int file = posix_open(filename, 0, 0); + int subsection_id = 1; + + bool global_header = true; + bool local_header = true; + bool code = false; + + while (true) { + char buffer[4096]; + int len = 0; + bool bad = true; + int backtick = 0; + while (posix_read(file, buffer + len, 1)) { + if (buffer[len] == '\n') { + bad = false; + break; + } + if (buffer[len] == '<' && code) { + _strcpy(buffer + len, "<"); + len += 2; + } + if (buffer[len] == '>' && code) { + _strcpy(buffer + len, ">"); + len += 2; + } + if (buffer[len] == '`' && !code) { + if (backtick == 0) { + _strcpy(buffer + len, ""); + len += 5; + } + else { + _strcpy(buffer + len, ""); + len += 6; + } + backtick = 1 - backtick; + } + len++; + } + if (bad) break; + buffer[len] = '\0'; + char *line = buffer; + + if (!_strncmp(line, "//*", 3) && _strlen(line) >= 4) { + if (code) { + _fputs(fd, "\n"); + code = false; + } + line += 4; + if (global_header) { + _fputsi(fd, "

"); + _fputs2(fd, line, "

\n"); + sections[section_id] = _strdup(line); + global_header = false; + } + else if (local_header) { + _fputsi(fd, "

", line, "

\n"); + subsections[section_id][subsection_id] = _strdup(line); + subsection_id++; + local_header = false; + } + else { + _fputs2(fd, line, "\n"); + } + } + else { + if (!code && _strlen(line) && !global_header) { + _fputs(fd, "
");
+                code = true;
+                local_header = true;
+            }
+            if (code) {
+                _fputs2(fd, line, "\n");
+            }
+        }
+    }
+    if (code) {
+        _fputs(fd, "
\n"); + code = false; + } + posix_close(file); +} + +int main(int argc, char **argv) { + int fd_contents[2]; + posix_pipe(fd_contents); + for (int i = 1; i < argc; i++) { + parse(i, argv[i], fd_contents[1]); + } + posix_close(fd_contents[1]); + char *str = read_file_descriptor(fd_contents[0]); + posix_close(fd_contents[0]); + + int out = STDOUT; + + _fputs(out, "\n"); + _fputs(out, "

Altlib Reference

\n"); + _fputs(out, "
\n"); + + _fputs(out, "
\n"); + _fputs(out, str); + _fputs(out, "
\n"); + + return 0; +} \ No newline at end of file diff --git a/altlib/header.html b/altlib/header.html new file mode 100644 index 0000000..9354881 --- /dev/null +++ b/altlib/header.html @@ -0,0 +1,70 @@ + + + + + + + + Altlib Reference + + diff --git a/altlib/memory.al b/altlib/memory.al index 867bd69..245cf89 100644 --- a/altlib/memory.al +++ b/altlib/memory.al @@ -1,2 +1,9 @@ +//* memory + +//* _memcpy +//* Copies the data of length `sz` bytes from `src` pointer to `dest` pointer. proto ._memcpy(dest #1I, src #1I, sz #I) -> #1I + +//* _memset +//* Sets the data of length `count` bytes to `dest` pointer with value `ch`. Important: only the lowest byte in `ch` argument is used. proto ._memset(dest #1I, ch #I, count #I) -> #1I diff --git a/altlib/posix.al b/altlib/posix.al index 1e72d54..8d8d71b 100644 --- a/altlib/posix.al +++ b/altlib/posix.al @@ -1,3 +1,6 @@ +//* posix + +//* todo proto .posix_read(fd #I, buffer #1C, count #I) -> #I proto .posix_write(fd #I, buffer #1C, count #I) -> #I proto .posix_open(filename #1C, flags #I, mode #I) -> #I diff --git a/altlib/stdio.al b/altlib/stdio.al index f9be51d..c81a514 100644 --- a/altlib/stdio.al +++ b/altlib/stdio.al @@ -2,15 +2,26 @@ include altlib."posix.al" include altlib."stdlib.al" include altlib."string.al" +//* stdio + +//* fputs_ +//* Prints the string `str` to the descriptor `fd`. Returns length of the string printed. func ^.fputs_(fd #I, str #1C) -> #I posix_write(fd, str, strlen_(str)) +//* fputs2_ +//* Prints the strings `str1` and `str2` to the descriptor `fd`. Returns length of the string printed. func ^.fputs2_(fd #I, str1 #1C, str2 #1C) -> #I fputs_(fd, str1) + fputs_(fd, str2) + +//* fputs3_ +//* Prints the strings `str1`, `str2` and `str3` to the descriptor `fd`. Returns length of the string printed. func ^.fputs3_(fd #I, str1 #1C, str2 #1C, str3 #1C) -> #I fputs_(fd, str1) + fputs_(fd, str2) + fputs_(fd, str3) +//* fputi_ +//* Prints the integer `n` to the descriptor `fd`. Returns length of the string printed. func ^.fputi_(fd #I, n #I) -> #I { def str := itoa_(n) def res := posix_write(fd, str, strlen_(str)) @@ -18,19 +29,27 @@ func ^.fputi_(fd #I, n #I) -> #I { return res } +//* fputsi_ +//* Prints the string `str1`, integer `x` and string `str2` to the descriptor `fd`. Returns length of the string printed. func ^.fputsi_(fd #I, str1 #1C, x #I, str2 #1C) -> #I fputs_(fd, str1) + fputi_(fd, x) + fputs_(fd, str2) +//* puts_ +//* Prints the string `str` to the standard output descriptor. Returns length of the string printed. func ^.puts_(str #1C) -> #I { def STDOUT := 1 return fputs_(STDOUT, str) + fputs_(STDOUT, "\n") } +//* puti_ +//* Prints the integer `n` to the standard output descriptor. Returns length of the string printed. func ^.puti_(n #I) -> #I { def STDOUT := 1 return fputi_(STDOUT, n) + fputs_(STDOUT, "\n") } +//* sputs_ +//* Copies the string `src` to string `dst`. Doesn't check for the length. Returns length of the string. func ^.sputs_(dst #1C, src #1C) -> #I { def i := 0 return while (src[i] <> '\0') { @@ -40,6 +59,8 @@ func ^.sputs_(dst #1C, src #1C) -> #I { else i } +//* sputi_ +//* Prints the integer `n` to the string `dst`. Doesn't check for the length. Returns length of the string printed. func ^.sputi_(dst #1C, n #I) -> #I { def str := itoa_(n) eval sputs_(dst, str) @@ -48,11 +69,15 @@ func ^.sputi_(dst #1C, n #I) -> #I { return res } +//* freadc_ +//* Reads and returns one character from the descriptor `fd`. func ^.freadc_(fd #I) -> #C { def c := '\0' return if (posix_read(fd, c&, 1) = 0) '\0' else c } +//* freads_ +//* Reads a string from the descriptor `fd` to the string `dst`. Doesn't check for the length. Returns the length of the string. Vulnerable function! func ^.freads_(fd #I, dst #1C) -> #I { def i := 0 def dsti := dst as #I @@ -74,6 +99,8 @@ func ^.freads_(fd #I, dst #1C) -> #I { return i } +//* freadi_ +//* Reads and returns a non-negative integer from the descriptor `fd`. Doesn't check for overflow. func ^.freadi_(fd #I) -> #I { def x := 0 def start := 0 @@ -88,16 +115,22 @@ func ^.freadi_(fd #I) -> #I { else 0 } +//* readc_ +//* Reads and returns a character from the stardard input descriptor. func ^.readc_() -> #C { def STDIN := 0 return freadc_(STDIN) } +//* reads_ +//* Reads a string character from the stardard input descriptor to `dst`. Returns size of the string. Vulnerable function! func ^.reads_(dst #1C) -> #I { def STDIN := 0 return freads_(STDIN, dst) } +//* readi_ +//* Reads and returns an integer from the stardard input descriptor. func ^.readi_() -> #I { def STDIN := 0 return freadi_(STDIN) diff --git a/altlib/stdlib.al b/altlib/stdlib.al index c270cd2..7d0bd10 100644 --- a/altlib/stdlib.al +++ b/altlib/stdlib.al @@ -1,3 +1,6 @@ +//* stdlib + +//* todo proto ._malloc(sz #I) -> #1I proto ._free(ptr #1I) -> #V diff --git a/altlib/string.al b/altlib/string.al index 97234e6..38da900 100644 --- a/altlib/string.al +++ b/altlib/string.al @@ -1,5 +1,7 @@ include altlib."stdlib.al" +//* string +//* todo func ^.strcpy_(a #1C, b #1C) -> #1C { def i := 0 return while (1) { diff --git a/altlib/test_allocator.al b/altlib/test_allocator.al index 472fd1f..88eee19 100644 --- a/altlib/test_allocator.al +++ b/altlib/test_allocator.al @@ -1,5 +1,8 @@ include altlib."posix.al" +//* test_allocator + +//* todo typedef TestAllocator := #S { data: #1I, size: #I, diff --git a/altlib/vector.al b/altlib/vector.al index 0c9f699..a6bb08d 100644 --- a/altlib/vector.al +++ b/altlib/vector.al @@ -2,6 +2,9 @@ include altlib."memory.al" include altlib."stdio.al" include altlib."stdlib.al" +//* vector + +//* todo typedef Vector := #S { data: #1I, size: #I, diff --git a/docs/altlibref.html b/docs/altlibref.html new file mode 100644 index 0000000..aafa0e6 --- /dev/null +++ b/docs/altlibref.html @@ -0,0 +1,558 @@ + + + + + + + + Altlib Reference + + + +

Altlib Reference

+ +
+

algorithm

+

min_

+Gets two integer values and returns the minimum one. +
func ^.min_(a #I, b #I) -> #I
+    if (a < b) a else b
+
+
+

max_

+Gets two integer values and returns the maximum one. +
func ^.max_(a #I, b #I) -> #I
+    if (a < b) b else a
+
+

cassert

+

assert_

+Gets one integer value and stop execution with return code 3, if the value is 0. +
func ^.assert_(x #I) -> #V {
+    eval if (not x) { eval posix_exit(3) }
+}
+
+

memory

+

_memcpy

+Copies the data of length sz bytes from src pointer to dest pointer. +
proto ._memcpy(dest #1I, src #1I, sz #I) -> #1I
+
+
+

_memset

+Sets the data of length count bytes to dest pointer with value ch. Important: only the lowest byte in ch argument is used. +
proto ._memset(dest #1I, ch #I, count #I) -> #1I
+
+

posix

+

todo

+
proto .posix_read(fd #I, buffer #1C, count #I) -> #I
+proto .posix_write(fd #I, buffer #1C, count #I) -> #I
+proto .posix_open(filename #1C, flags #I, mode #I) -> #I
+proto .posix_close(fd #I) -> #I
+proto .posix_mmap(start #1I, length #I, prot #I, flags #I, fd #I, offset #I) -> #1I
+proto .posix_munmap(start #1I, length #I) -> #I
+proto .posix_fork() -> #I
+proto .posix_execve(filename #1I, argv #2C, envp #2C) -> #I
+proto .posix_exit(error_code #I) -> #I
+proto .posix_wait4(pid #I, stat_addr #1I, options #I, rusage #1I) -> #I
+proto .posix_unlink(pathname #1I) -> #I
+
+

stdio

+

fputs_

+Prints the string str to the descriptor fd. Returns length of the string printed. +
func ^.fputs_(fd #I, str #1C) -> #I
+    posix_write(fd, str, strlen_(str))
+
+
+

fputs2_

+Prints the strings str1 and str2 to the descriptor fd. Returns length of the string printed. +
func ^.fputs2_(fd #I, str1 #1C, str2 #1C) -> #I
+    fputs_(fd, str1) + fputs_(fd, str2)
+
+
+
+

fputs3_

+Prints the strings str1, str2 and str3 to the descriptor fd. Returns length of the string printed. +
func ^.fputs3_(fd #I, str1 #1C, str2 #1C, str3 #1C) -> #I
+    fputs_(fd, str1) + fputs_(fd, str2) + fputs_(fd, str3)
+
+
+

fputi_

+Prints the integer n to the descriptor fd. Returns length of the string printed. +
func ^.fputi_(fd #I, n #I) -> #I {
+    def str := itoa_(n)
+    def res := posix_write(fd, str, strlen_(str))
+    eval _free(str as #1I)
+    return res
+}
+
+
+

fputsi_

+Prints the string str1, integer x and string str2 to the descriptor fd. Returns length of the string printed. +
func ^.fputsi_(fd #I, str1 #1C, x #I, str2 #1C) -> #I
+    fputs_(fd, str1) + fputi_(fd, x) + fputs_(fd, str2)
+
+
+

puts_

+Prints the string str to the standard output descriptor. Returns length of the string printed. +
func ^.puts_(str #1C) -> #I {
+    def STDOUT := 1
+    return fputs_(STDOUT, str) + fputs_(STDOUT, "\n")
+}
+
+
+

puti_

+Prints the integer n to the standard output descriptor. Returns length of the string printed. +
func ^.puti_(n #I) -> #I {
+    def STDOUT := 1
+    return fputi_(STDOUT, n) + fputs_(STDOUT, "\n")
+}
+
+
+

sputs_

+Copies the string src to string dst. Doesn't check for the length. Returns length of the string. +
func ^.sputs_(dst #1C, src #1C) -> #I {
+    def i := 0
+    return while (src[i] <> '\0') {
+        dst[i]& <- src[i]
+        i := i + 1
+    }
+    else i
+}
+
+
+

sputi_

+Prints the integer n to the string dst. Doesn't check for the length. Returns length of the string printed. +
func ^.sputi_(dst #1C, n #I) -> #I {
+    def str := itoa_(n)
+    eval sputs_(dst, str)
+    def res := strlen_(str)
+    eval _free(str as #1I)
+    return res
+}
+
+
+

freadc_

+Reads and returns one character from the descriptor fd. +
func ^.freadc_(fd #I) -> #C {
+    def c := '\0'
+    return if (posix_read(fd, c&, 1) = 0) '\0' else c
+}
+
+
+

freads_

+Reads a string from the descriptor fd to the string dst. Doesn't check for the length. Returns the length of the string. Vulnerable function! +
func ^.freads_(fd #I, dst #1C) -> #I {
+    def i := 0
+    def dsti := dst as #I
+    eval while (1) {
+        def size := posix_read(fd, (dsti + i) as #1C, 1)
+        eval if (size = 0) { break {} }
+        def ch := dst[i]
+        eval if (ch = ' ' or ch = '\n') {
+            eval if (i = 0) {
+                i := i - 1
+            }
+            else {
+                break {}
+            }
+        }
+        i := i + 1
+    }
+    dst[i]& <- '\0'
+    return i
+}
+
+
+

freadi_

+Reads and returns a non-negative integer from the descriptor fd. Doesn't check for overflow. +
func ^.freadi_(fd #I) -> #I {
+    def x := 0
+    def start := 0
+    return while (1) {
+        def c := freadc_(fd)
+        eval if ((c = ' ' or c = '\n') and start = 0) { continue }
+        start := 1
+        eval if (not (c >= '0' and c <= '9')) { break x }
+        def d := (c - '0') as #I
+        x := x * 10 + d
+    }
+    else 0
+}
+
+
+

readc_

+Reads and returns a character from the stardard input descriptor. +
func ^.readc_() -> #C {
+    def STDIN := 0
+    return freadc_(STDIN)
+}
+
+
+

reads_

+Reads a string character from the stardard input descriptor to dst. Returns size of the string. Vulnerable function! +
func ^.reads_(dst #1C) -> #I {
+    def STDIN := 0
+    return freads_(STDIN, dst)
+}
+
+
+

readi_

+Reads and returns an integer from the stardard input descriptor. +
func ^.readi_() -> #I {
+    def STDIN := 0
+    return freadi_(STDIN)
+}
+
+

stdlib

+

todo

+
proto ._malloc(sz #I) -> #1I
+proto ._free(ptr #1I) -> #V
+
+func ^.itoa_(n #I) -> #1C {
+    return if (n = 0) {
+        def str := _malloc(2 * $#C) as #1C
+        str[0]& <- '0'
+        str[1]& <- '\0'
+        return str
+    }
+    else {
+        def sign := 1
+        eval if (n < 0) {
+            sign := -1
+            n := -n
+        }
+
+        def len := 0
+        def m := n
+        eval while (m) {
+            len := len + 1
+            m := m / 10
+        }
+        eval if (sign = -1) {
+            len := len + 1
+        }
+
+        def str := _malloc((len + 1) * $#C) as #1C
+            eval if (sign = -1) {
+            str[0]& <- '-'
+        }
+        str[len]& <- '\0'
+        len := len - 1
+        eval while (n) {
+            def val := n % 10 as #C
+            str[len]& <- val + '0'
+            n := n / 10
+            len := len - 1
+        }
+        return str
+    }
+}
+
+/* func ^.atoi_(str #1C) -> #I {
+    def i := strlen_(str) - 1
+    def x := 0
+    eval while (i >= 0) {
+        def ch := (str[i] - '0') as #I
+        x := x * 10 + ch
+        i := i - 1
+    }
+    return x
+} */
+
+func ^.rand_(seed #I) -> #I {
+    seed := seed * 1103515245 + 12345
+    return (seed / 65536) % 32768
+}
+
+

string

+

todo

+
func ^.strcpy_(a #1C, b #1C) -> #1C {
+    def i := 0
+    return while (1) {
+        a[i]& <- b[i]
+        eval if (b[i] = '\0') { break a }
+        i := i + 1
+    } else a
+}
+
+func ^.strncpy_(a #1C, b #1C, n #I) -> #1C {
+    def i := 0
+    return while (i < n) {
+        a[i]& <- b[i]
+        eval if (b[i] = '\0') { break a }
+        i := i + 1
+    } else a
+}
+
+func ^.strcmp_(a #1C, b #1C) -> #I {
+    def i := 0
+    return while (1) {
+        eval if (a[i] < b[i]) { break -1 }
+        eval if (b[i] < a[i]) { break 1 }
+        eval if (a[i] = '\0' or b[i] = '\0') { break 0 }
+        i := i + 1
+    } else 0
+}
+
+func ^.strncmp_(a #1C, b #1C, n #I) -> #I {
+    def i := 0
+    return while (i < n) {
+        eval if (a[i] < b[i]) { break -1 }
+        eval if (b[i] < a[i]) { break 1 }
+        eval if (a[i] = '\0' or b[i] = '\0') { break 0 }
+        i := i + 1
+    } else 0
+}
+
+func ^.strlen_(a #1C) -> #I {
+    def i := 0
+    return while (1) {
+        eval if (a[i] = '\0') { break i }
+        i := i + 1
+    } else 0
+}
+
+func ^.concat_(a #1C, b #1C) -> #1C {
+    def s_a := strlen_(a)
+    def s_b := strlen_(b)
+    def buf := _malloc(s_a + s_b + 1) as #1C
+    def i := 0
+    eval while (i < s_a) {
+        buf[i]& <- a[i]
+        i := i + 1
+    }
+    i := 0
+    eval while (i < s_b) {
+        buf[s_a + i]& <- b[i]
+        i := i + 1
+    }
+    buf[s_a + s_b]& <- '\0'
+    return buf
+}
+
+func ^.concat3_(a #1C, b #1C, c #1C) -> #1C {
+    def s_a := strlen_(a)
+    def s_b := strlen_(b)
+    def s_c := strlen_(c)
+    def buf := _malloc(s_a + s_b + s_c + 1) as #1C
+    def i := 0
+    eval while (i < s_a) {
+        buf[i]& <- a[i]
+        i := i + 1
+    }
+    i := 0
+    eval while (i < s_b) {
+        buf[s_a + i]& <- b[i]
+        i := i + 1
+    }
+    i := 0
+    eval while (i < s_c) {
+        buf[s_a + s_b + i]& <- c[i]
+        i := i + 1
+    }
+    buf[s_a + s_b + s_c]& <- '\0'
+    return buf
+}
+
+func ^.substr_(a #1C, n #I) -> #1C {
+    def m := strlen_(a)
+    eval if (m <= n) {
+        n := m
+    }
+    def b := _malloc(n + 1) as #1C
+    def i := 0
+    eval while (i < n) {
+        b[i]& <- a[i]
+        i := i + 1
+    }
+    b[n]& <- '\0'
+    return b
+}
+
+

test_allocator

+

todo

+
typedef TestAllocator := #S {
+    data: #1I,
+    size: #I,
+    reserved: #I
+};
+
+func ^#1TestAllocator.init(this #1TestAllocator, size #I) -> #V {
+    def PROT_READ := 1
+    def PROT_WRITE := 2
+    def MAP_PRIVATE := 2
+    def MAP_ANONYMOUS := 32
+    this->data& <- posix_mmap(0 as #1I, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)
+    this->size& <- 0
+    this->reserved& <- size
+}
+
+func ^#1TestAllocator.deinit(this #1TestAllocator) -> #V {
+    eval posix_munmap(this->data, this->reserved)
+}
+
+func ^#1TestAllocator.alloc(this #1TestAllocator, size #I) -> #1I {
+    return if (this->size + size <= this->reserved) {
+        def x := this->data as #I
+        def ptr := (x + this->size) as #1I
+        this->size& <- this->size + size
+        return ptr
+    }
+    else 0 as #1I
+}
+
+

vector

+

todo

+
typedef Vector := #S {
+    data: #1I,
+    size: #I,
+    reserved: #I
+}
+
+func ^.vector_init() -> #1Vector {
+    def this #1Vector := _malloc($#Vector) as #1Vector
+    this->size& <- 0 
+    this->reserved& <- 10
+    this->data& <- _malloc(this->reserved * $#I)
+    return this
+}
+
+func ^#1Vector.push(this #1Vector, x #I) -> #V {
+    eval if (this->size = this->reserved) {
+        def buffer #1I := _malloc(this->reserved * 2 * $#I)
+        eval puti_(this->data as #I)
+        eval _memcpy(buffer, this->data, this->size * $#I)
+        eval _free(this->data)
+        this->data& <- buffer
+        this->reserved& <- this->reserved * 2
+    }
+    this->data[this->size]& <- x
+    this->size& <- this->size + 1
+}
+
+func ^#1Vector.pop(this #1Vector) -> #I {
+    return if (this->size = 0) { return 0 }
+    else {
+        this->size& <- this->size - 1
+        return 1
+    }
+}
+
+func ^#1Vector.get(this #1Vector, x #I) -> #I {
+    return this->data[x]
+}
+
+