aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore6
-rw-r--r--CMakeLists.txt12
-rw-r--r--json.c113
-rw-r--r--json.h13
-rw-r--r--log.c11
-rw-r--r--log.h7
-rw-r--r--main.c47
-rw-r--r--memory.c27
-rw-r--r--memory.h15
-rw-r--r--string.c33
-rw-r--r--string.h17
-rw-r--r--vec.c34
-rw-r--r--vec.h20
13 files changed, 355 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..e7ea508
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+main
+
+cmake_install.cmake
+Makefile
+CMakeFiles/
+CMakeCache.txt
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..c94bd65
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,12 @@
+cmake_minimum_required(VERSION 3.30.5)
+project(kagamic VERSION 0.1 LANGUAGES C)
+add_executable(main
+ main.c
+ string.h string.c
+ memory.h memory.c
+ vec.h vec.c
+ json.h json.c
+ log.h log.c
+)
+target_link_libraries(main m)
+target_compile_options(main PRIVATE -Wall)
diff --git a/json.c b/json.c
new file mode 100644
index 0000000..e68d617
--- /dev/null
+++ b/json.c
@@ -0,0 +1,113 @@
+#include "json.h"
+
+#include <assert.h>
+#include <ctype.h>
+#include <math.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "string.h"
+
+typedef struct {
+ int value;
+ uintptr_t pos;
+} parse_integer_result;
+
+parse_integer_result parse_integer(Arena *a, Str src, uintptr_t pos) {
+ int *ints = new (a, int, 16); // TODO: reuse in parsing
+ int i = 0;
+ while (isdigit(src.data[pos + i])) {
+ int val = (src.data[pos + i] - '0');
+ ints[i] = val;
+ i++;
+ }
+ int result = 0;
+ for (int j = 0; j < i; j++) {
+ result += ints[j] * pow(10, (i - j - 1));
+ }
+ printf("json.parse_integer: parsed int=%d at pos=%lu\n", result, pos);
+ return (parse_integer_result){result, pos + i};
+}
+
+uintptr_t absorb_whitespaces(Str src, uintptr_t pos) {
+ int i = 0;
+ while (isspace(src.data[pos + i])) {
+ i++;
+ }
+ return pos + i;
+}
+
+typedef struct {
+ Vec *items;
+ uintptr_t pos;
+} parse_array_result;
+
+parse_array_result parse_array(Arena *a, Str src, uintptr_t start_pos) {
+ printf("json.parse_array: parsing array %s\n", src.data + start_pos);
+ assert(src.data[start_pos] == '[');
+ uintptr_t pos = start_pos + 1;
+ Vec *items = Vec_new(a, JSON, 0);
+ for (;;) {
+ pos = absorb_whitespaces(src, pos);
+ parse_integer_result result = parse_integer(a, src, pos);
+ assert(result.pos > pos);
+ items = Vec_push(a, items, &result.value);
+ pos = result.pos;
+ pos = absorb_whitespaces(src, pos);
+ if (src.data[pos] == ',') {
+ pos++;
+ } else {
+ break;
+ }
+ };
+ assert(src.data[pos] == ']');
+
+ return (parse_array_result){items, pos + 1};
+}
+
+typedef struct {
+ Str string;
+ uintptr_t pos;
+} parse_string_result;
+
+parse_string_result parse_string(Arena *a, Str src, uintptr_t pos) {
+ printf("json.parse_string: %s", src.data + pos);
+ assert(src.data[pos] == '"');
+ int i = 1;
+
+ while (src.data[pos + i] != '"' && src.data[pos + i - 1] != '\\') {
+ i++;
+ assert(i + pos <= src.len);
+ }
+ assert(src.data[pos + i]);
+ char *s;
+ memcpy(s, src.data + pos + 1, i - 1);
+
+ printf("%s", s);
+
+ return (parse_string_result){Str_copy(a, src.data + pos + 1, i - 1), pos + i};
+}
+
+JSON JSON_parse(Arena *a, Str src) {
+ JSON json = {0};
+ int pos = 0;
+ // printf("json.parse: src=%s", src.data);
+ if (isdigit(src.data[pos])) {
+ parse_integer_result result = parse_integer(a, src, 0);
+ json.integer = &result.value;
+ pos = result.pos;
+ }
+ if (src.data[pos] == '[') {
+ parse_array_result result = parse_array(a, src, pos);
+ json.array = result.items;
+ pos = result.pos;
+ }
+ if (src.data[pos] == '"') {
+ parse_string_result result = parse_string(a, src, pos);
+ json.string = &result.string;
+ pos = result.pos;
+ }
+
+ return json;
+}
diff --git a/json.h b/json.h
new file mode 100644
index 0000000..588cb6b
--- /dev/null
+++ b/json.h
@@ -0,0 +1,13 @@
+#ifndef JSON_H
+#define JSON_H
+#include "memory.h"
+#include "string.h"
+#include "vec.h"
+
+typedef struct {
+ int *integer;
+ Vec *array;
+ Str *string;
+} JSON;
+JSON JSON_parse(Arena *a, Str src);
+#endif
diff --git a/log.c b/log.c
new file mode 100644
index 0000000..9a3211f
--- /dev/null
+++ b/log.c
@@ -0,0 +1,11 @@
+#include "log.h"
+
+#include <stdio.h>
+
+void info(Logger l, const char *name, const char *str, ...) {
+ if (l.level >= INFO) {
+ printf("[%s] ", name);
+ printf(str);
+ printf("\n");
+ }
+};
diff --git a/log.h b/log.h
new file mode 100644
index 0000000..51ce333
--- /dev/null
+++ b/log.h
@@ -0,0 +1,7 @@
+typedef enum { INFO } LogLevel;
+
+typedef struct {
+ LogLevel level;
+} Logger;
+
+void info(Logger l, const char *name, const char *str, ...);
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..0910b3d
--- /dev/null
+++ b/main.c
@@ -0,0 +1,47 @@
+/*
+Inspirations:
+- https://nullprogram.com/
+*/
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include "json.h"
+#include "memory.h"
+#include "string.h"
+#include "vec.h"
+
+#define sizeof(x) (ptrdiff_t)sizeof(x)
+#define countof(a) (sizeof(a) / sizeof(*(a)))
+#define lengthof(s) (countof(s) - 1)
+
+typedef struct {
+ int age;
+} User;
+
+int main() {
+ Arena perm = Arena_new(128e3);
+ assert(Str_equals(S("Bonjour"), S("Bonjour")));
+ // Testing JSON
+ printf("Arena: mem=%d B\n", Arena_get_used(perm));
+ JSON json_int = JSON_parse(&perm, S("123"));
+ assert(*json_int.integer == 123);
+ printf("Arena: mem=%d B\n", Arena_get_used(perm));
+ JSON json_int_array = JSON_parse(&perm, S("[1,2,3]"));
+ assert(json_int_array.integer == NULL);
+ assert(json_int_array.array->len == 3);
+ int sum = 0;
+ for (int i = 0; i < json_int_array.array->len; i++) {
+ sum += *Vec_get(json_int_array.array, int, i);
+ }
+ assert(sum == 6);
+ printf("Arena: mem=%d B\n", Arena_get_used(perm));
+ assert(*Vec_get(JSON_parse(&perm, S("[1, 2, 3]")).array, int, 1) == 2);
+ printf("Arena: mem=%d B\n", Arena_get_used(perm));
+ Str a = S("\"abc\"");
+ JSON s = JSON_parse(&perm, S("\"abc\""));
+ // printf("%s (%d)\n", s.string->data, s.string->len);
+ // assert(Str_equals(*JSON_parse(&perm, S("\"abc\"")).string, S("abc")) == 1);
+ return 0;
+}
diff --git a/memory.c b/memory.c
new file mode 100644
index 0000000..cfb5dd4
--- /dev/null
+++ b/memory.c
@@ -0,0 +1,27 @@
+#include <assert.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "memory.h"
+
+Arena Arena_new(ptrdiff_t cap) {
+ Arena a = {0};
+ a.cap = cap;
+ a.beg = malloc(cap);
+ a.end = a.beg ? a.beg + cap : 0;
+ return a;
+}
+
+// Magic to allow optimisation __attribute((malloc, alloc_size(2, 4),
+// alloc_align(3)))
+void *alloc(Arena *a, ptrdiff_t count, int size, int align) {
+ int padding = -(uintptr_t)a->beg & (align - 1);
+ assert(count < (a->end - a->beg - padding) / size);
+ void *cursor = a->beg + padding;
+ a->beg += padding + count * size;
+ return memset(cursor, 0, count * size);
+}
+
+int Arena_get_used(Arena a) { return a.cap - (a.end - a.beg); }
diff --git a/memory.h b/memory.h
new file mode 100644
index 0000000..e1c5fdd
--- /dev/null
+++ b/memory.h
@@ -0,0 +1,15 @@
+#include <stddef.h>
+
+#ifndef MEMORY_H
+#define MEMORY_H
+typedef struct {
+ ptrdiff_t cap;
+ char *beg;
+ char *end;
+} Arena;
+
+Arena Arena_new(ptrdiff_t cap);
+#define new(a, T, n) (T *)alloc(a, n, sizeof(T), _Alignof(T))
+void *alloc(Arena *a, ptrdiff_t count, int size, int align);
+int Arena_get_used(Arena a);
+#endif
diff --git a/string.c b/string.c
new file mode 100644
index 0000000..509163f
--- /dev/null
+++ b/string.c
@@ -0,0 +1,33 @@
+#include "string.h"
+
+#include <stdint.h>
+#include <string.h>
+
+#include "memory.h"
+
+Str *Str_new(Arena *a, uintptr_t len) {
+ Str *s = new (a, Str, 1);
+ s->data = new (a, char, len);
+ return s;
+}
+
+int Str_equals(Str a, Str b) {
+ return (a.len == b.len) && (!a.len || !memcmp(a.data, b.data, a.len));
+}
+
+uint64_t Str_hash64(Str s) {
+ uint64_t h = 0x100;
+ for (ptrdiff_t i = 0; i < s.len; i++) {
+ h ^= s.data[i] & 255;
+ h *= 1111111111111111111;
+ }
+ return h;
+}
+
+Str Str_copy(Arena *a, char *data, uintptr_t len) {
+ Str str = {0};
+ str.data = new (a, char, len);
+ if (str.len)
+ memcpy(str.data, data, len);
+ return str;
+}
diff --git a/string.h b/string.h
new file mode 100644
index 0000000..c441373
--- /dev/null
+++ b/string.h
@@ -0,0 +1,17 @@
+#include <stddef.h>
+#include <stdint.h>
+
+#include "memory.h"
+
+#ifndef STRING_H
+#define STRING_H
+#define S(s) (Str){s, sizeof(s) - 1}
+typedef struct {
+ char *data;
+ ptrdiff_t len;
+} Str;
+Str *Str_new(Arena *a, uintptr_t len);
+int Str_equals(Str a, Str b);
+uint64_t Str_hash64(Str s);
+Str Str_copy(Arena *a, char *data, uintptr_t len);
+#endif
diff --git a/vec.c b/vec.c
new file mode 100644
index 0000000..6962d03
--- /dev/null
+++ b/vec.c
@@ -0,0 +1,34 @@
+#include <stdio.h>
+#include <string.h>
+
+#include "vec.h"
+
+Vec *_Vec_new(Arena *a, int size, ptrdiff_t cap, int align) {
+ Vec *v = new (a, Vec, 1);
+ v->data = alloc(a, cap, size, align);
+ v->size = size;
+ v->align = align;
+ v->cap = cap;
+ v->len = 0;
+ return v;
+}
+
+Vec *Vec_push(Arena *a, Vec *v, void *data) {
+ // printf("push: dest=%p, src=%p, size=%d\n", v->data + v->len * v->size,
+ // data,
+ // v->size);
+ if (v->len == v->cap) {
+ void *cpy = alloc(a, v->cap * 2, v->size, v->align);
+ memcpy(cpy, v->data, v->len * v->size);
+ v->cap *= 2;
+ }
+ memcpy(v->data + v->len * v->size, data, v->size);
+ v->len++;
+ return v;
+}
+
+void *_Vec_get(Vec *v, int pos) {
+ // printf("get: length=%lu, cap=%lu, pos=%d\n", v->len, v->cap, pos);
+ // printf("get: start=%p, asked=%p\n", v->data, v->data + v->size * pos);
+ return v->data + v->size * pos;
+}
diff --git a/vec.h b/vec.h
new file mode 100644
index 0000000..9fb9590
--- /dev/null
+++ b/vec.h
@@ -0,0 +1,20 @@
+#include <stddef.h>
+#include <stdint.h>
+
+#include "memory.h"
+
+#ifndef VEC_H
+#define VEC_H
+typedef struct {
+ void *data;
+ ptrdiff_t len;
+ ptrdiff_t cap;
+ uintptr_t size;
+ int align;
+} Vec;
+#define Vec_new(a, T, cap) _Vec_new(a, sizeof(T), cap, _Alignof(T))
+Vec *_Vec_new(Arena *a, int size, ptrdiff_t cap, int align);
+Vec *Vec_push(Arena *a, Vec *v, void *data);
+#define Vec_get(v, T, p) (T *)_Vec_get(v, p)
+void *_Vec_get(Vec *v, int pos);
+#endif