NAME=ccera.a
-SRCS=src/arc.c src/eval.c src/value_destroy.c src/value_get.c src/value_lifetime.c src/value_new.c
+SRCS=src/arc.c src/defer2.c src/defer.c src/eval.c src/panic.c src/value_destroy.c src/value_get.c src/value_lifetime.c src/value_new.c src/value_readf.c
HEADERS=src/ccera.h
OBJS=${SRCS:src/%.c=${BUILDDIR}/%.o}
-CFLAGS=-Wall -Wextra -Werror -g -pthread -flto -ffat-lto-objects
-#CFLAGS=-Wall -Wextra -Werror -g -pthread -O3 -flto -ffat-lto-objects
+# no malloc leak detection as our union shenanigans trigger false positives
+CFLAGS=-Wall -Wextra -Werror -g -pthread -flto -ffat-lto-objects -fanalyzer -Wno-analyzer-malloc-leak
+CFLAGS += -O3
CC=gcc
MAKEFLAGS += --no-print-directory
-all : ${NAME}
+all: ${NAME}
-${BUILDDIR}/%.o : src/%.c ${HEADERS} ${THIS} | ${BUILDDIR}
+${BUILDDIR}/%.o: src/%.c ${HEADERS} ${THIS} | ${BUILDDIR}
${CC} ${CFLAGS} -c -o $@ $<
-${BUILDDIR} :
+${BUILDDIR}:
mkdir ${BUILDDIR}
-${NAME} : ${OBJS} ${THIS}
+${NAME}: ${OBJS} ${THIS}
${AR} rcs $@ ${OBJS}
-clean :
+clean:
rm -f ${OBJS}
-fclean : clean
+fclean: clean
rm -f ${NAME}
rm -fd ${BUILDDIR}
-re : fclean all
+re: fclean all
-remakefile : clean
+remakefile: clean
sed -i "s?^SRCS=.*?$$(echo -n SRCS=; echo -n src/*.c)?" ${THIS}
sed -i "s?^HEADERS=.*?$$(echo -n HEADERS=; echo -n src/*.h)?" ${THIS}
@norminette ${SRCS} ${HEADERS} > .norm || touch .norm_fail
norm: .norm
- @cat .norm
+ @cat .norm | sed "s/.*OK!$$//" | grep .
@test ! -e .norm_fail
norm-watch:
build-watch:
watch -c -n 1 make
-.PHONY : all clean fclean re remakefile norm norm-watch build-watch
+a.out: test.c ${NAME} ${THIS}
+ ${CC} ${CFLAGS} test.c ccera.a
+
+test: a.out
+ valgrind ./a.out
+
+.PHONY: all clean fclean re remakefile norm norm-watch build-watch test
/* By: agilliar <agilliar@student.42mulhouse.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/04/29 16:40:27 by agilliar #+# #+# */
-/* Updated: 2026/05/04 02:01:19 by agilliar ### ########.fr */
+/* Updated: 2026/05/05 20:40:03 by agilliar ### ########.fr */
/* */
/* ************************************************************************** */
t_usize *res;
if (__builtin_add_overflow(size, sizeof(t_usize), &size))
- return (NULL);
+ panic("Arc alloc too big to create");
res = malloc(size);
if (!res)
- return (NULL);
+ panic("Malloc failed while creating arc");
res[0] = 1;
return ((void *) &res[1]);
}
-t_arc arc_copy(t_arc arc)
+void arc_copy(t_arc arc)
{
- if (!arc)
- return (NULL);
if (__atomic_add_fetch(((t_usize *)arc) - 1, 1, __ATOMIC_RELAXED)
- < ((t_usize) 1) << (sizeof(t_usize) * 8 - 1))
- return (arc);
- arc_destroy(arc, noop);
- return (NULL);
+ >= ((t_usize) 1) << (sizeof(t_usize) * 8 - 1))
+ panic("Arc counter overflowed");
}
void arc_destroy(t_arc arc, t_drop destructor)
return ;
__atomic_thread_fence(__ATOMIC_ACQUIRE);
destructor(arc);
- free(arc - 8);
+ free(((char *)arc) - 8);
}
bool arc_is_unique(t_arc arc)
/* By: agilliar <agilliar@student.42mulhouse.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/04/29 16:08:57 by agilliar #+# #+# */
-/* Updated: 2026/05/04 03:58:26 by agilliar ### ########.fr */
+/* Updated: 2026/05/06 02:32:20 by agilliar ### ########.fr */
/* */
/* ************************************************************************** */
typedef uintptr_t t_usize;
typedef intptr_t t_isize;
+struct s_defer_pair
+{
+ void (*f)(void *);
+ void *dat;
+ bool err;
+};
+
+# define MAX_DEFERS 8
+
+typedef struct s_defer
+{
+ struct s_defer *prev;
+ struct s_defer *next;
+ t_usize len;
+ struct s_defer_pair defers[MAX_DEFERS];
+} t_defer;
+
+void defer_new(t_defer *store);
+void defer_delete(t_defer *store);
+void defer_re(t_defer *store);
+
+void defer(void *f, void *dat);
+void errdefer(void *f, void *dat);
+void defer_exit(t_defer *until);
+
+typedef struct s_panic_info
+{
+ void *data;
+ intptr_t jmp[5];
+ t_defer *defer;
+} t_panic_info;
+
+void *catch(void (f)(void *), void *dat);
+
+void panic(void *err)
+ __attribute__((noreturn, nonnull(1)));
+bool panicking(void);
+
typedef union u_value t_value;
typedef t_value (*t_builtin)(t_value);
{
t_usize len;
enum e_value_ptr discrim;
- t_value list[0];
+ t_value list[];
} t_value_list;
typedef struct s_value_bytes
{
t_usize len;
enum e_value_ptr discrim;
- char bytes[0];
+ char bytes[];
} t_value_bytes;
t_value value_builtin_new(t_builtin builtin);
t_value_bytes *value_bytes_get(t_value value);
t_isize value_int_get(t_value value);
-void value_destroy(t_value value);
+void value_destroy(t_value *value);
t_value value_copy(t_value value);
t_value_list *value_list_unique(t_value *value);
typedef void (*t_drop)(void *);
t_arc arc_create(t_usize size);
-t_arc arc_copy(t_arc arc);
+void arc_copy(t_arc arc);
void arc_destroy(t_arc arc, void (*destructor)(void *));
bool arc_is_unique(t_arc arc);
void noop(void *ptr);
-struct s_exec_context;
-
// The expression value is a tuple of an evaluatable and the argument to give it
//
// Value-evaluatables are laid out as follows:
--- /dev/null
+/* ************************************************************************** */
+/* */
+/* ::: :::::::: */
+/* defer.c :+: :+: :+: */
+/* +:+ +:+ +:+ */
+/* By: agilliar <agilliar@student.42mulhouse.fr> +#+ +:+ +#+ */
+/* +#+#+#+#+#+ +#+ */
+/* Created: 2026/05/05 17:31:36 by agilliar #+# #+# */
+/* Updated: 2026/05/06 02:31:46 by agilliar ### ########.fr */
+/* */
+/* ************************************************************************** */
+
+#include "ccera.h"
+#include <stddef.h>
+
+t_defer **defer_store(void);
+
+void defer(void *f, void *dat)
+{
+ t_defer *store;
+
+ store = *defer_store();
+ if (store->len == MAX_DEFERS)
+ {
+ ((void (*)(void *))f)(dat);
+ panic("Maximum defers exeeded in scope");
+ }
+ store->defers[store->len].f = f;
+ store->defers[store->len].dat = dat;
+ store->defers[store->len].err = false;
+ store->len++;
+}
+
+void errdefer(void *f, void *dat)
+{
+ t_defer *store;
+
+ store = *defer_store();
+ if (store->len == MAX_DEFERS)
+ {
+ ((void (*)(void *))f)(dat);
+ panic("Maximum defers exeeded in scope");
+ }
+ store->defers[store->len].f = f;
+ store->defers[store->len].dat = dat;
+ store->defers[store->len].err = true;
+ store->len++;
+}
+
+void defer_exit(t_defer *until)
+{
+ t_usize i;
+ t_defer *store;
+ struct s_defer_pair curr;
+
+ store = *defer_store();
+ while (store)
+ {
+ i = 0;
+ while (i < store->len)
+ {
+ curr = store->defers[i++];
+ if (!panicking() && curr.err)
+ continue ;
+ curr.f(curr.dat);
+ }
+ if (store == until)
+ break ;
+ store = store->prev;
+ }
+ *defer_store() = store;
+}
--- /dev/null
+/* ************************************************************************** */
+/* */
+/* ::: :::::::: */
+/* defer2.c :+: :+: :+: */
+/* +:+ +:+ +:+ */
+/* By: agilliar <agilliar@student.42mulhouse.fr> +#+ +:+ +#+ */
+/* +#+#+#+#+#+ +#+ */
+/* Created: 2026/05/06 02:23:38 by agilliar #+# #+# */
+/* Updated: 2026/05/06 02:32:07 by agilliar ### ########.fr */
+/* */
+/* ************************************************************************** */
+
+#include "ccera.h"
+#include <stddef.h>
+
+t_defer **defer_store(void)
+{
+ static __thread t_defer *store = NULL;
+
+ return (&store);
+}
+
+void defer_new(t_defer *store)
+{
+ store->len = 0;
+ store->prev = *defer_store();
+ if (store->prev)
+ store->prev->next = store;
+ store->next = NULL;
+ *defer_store() = store;
+}
+
+void defer_delete(t_defer *store)
+{
+ if (store == *defer_store())
+ *defer_store() = store->prev;
+ if (store->next)
+ store->next->prev = store->prev;
+ if (store->prev)
+ store->prev->next = store->next;
+}
+
+void defer_re(t_defer *store)
+{
+ defer_delete(store);
+ defer_new(store);
+}
/* By: agilliar <agilliar@student.42mulhouse.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/05/04 01:21:34 by agilliar #+# #+# */
-/* Updated: 2026/05/04 04:12:32 by agilliar ### ########.fr */
+/* Updated: 2026/05/05 05:31:52 by agilliar ### ########.fr */
/* */
/* ************************************************************************** */
#include "ccera.h"
#include <stdlib.h>
-
-static bool to_state(t_value *value)
-{
- t_value_list *expr;
- t_value_list *state;
-
- expr = value_list_unique(value);
- if (!expr || expr->len != 2)
- return (false);
- state = value_list_unique(&expr->list[0]);
- if (!state || state->len != 2)
- return (false);
- if (!value_list_unique(&state->list[0]))
- return (false);
- return (true);
-}
-
-t_value expr_eval(t_value expr)
-{
- to_state(&expr);
- value_destroy(expr);
- return (value_undefined_new());
-}
--- /dev/null
+/* ************************************************************************** */
+/* */
+/* ::: :::::::: */
+/* panic.c :+: :+: :+: */
+/* +:+ +:+ +:+ */
+/* By: agilliar <agilliar@student.42mulhouse.fr> +#+ +:+ +#+ */
+/* +#+#+#+#+#+ +#+ */
+/* Created: 2026/05/05 15:38:33 by agilliar #+# #+# */
+/* Updated: 2026/05/05 21:25:00 by agilliar ### ########.fr */
+/* */
+/* ************************************************************************** */
+
+#include "ccera.h"
+#include <string.h>
+#include <stddef.h>
+#include <stdint.h>
+
+static t_panic_info *panic_store(void)
+{
+ static __thread t_panic_info store;
+
+ return (&store);
+}
+
+void *catch(void (f)(void *), void *dat)
+{
+ void *res;
+ t_defer defer_store;
+ t_panic_info prev;
+
+ prev = *panic_store();
+ panic_store()->defer = &defer_store;
+ defer_new(&defer_store);
+ if (__builtin_setjmp(panic_store()->jmp))
+ {
+ res = panic_store()->data;
+ *panic_store() = prev;
+ return (res);
+ }
+ f(dat);
+ *panic_store() = prev;
+ return (NULL);
+}
+
+__attribute__((noreturn, nonnull(1)))
+void panic(void *err)
+{
+ defer_exit(panic_store()->defer);
+ panic_store()->data = err;
+ __builtin_longjmp(panic_store()->jmp, 1);
+}
+
+bool panicking(void)
+{
+ return (panic_store()->data != NULL);
+}
/* By: agilliar <agilliar@student.42mulhouse.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/04/30 19:40:43 by agilliar #+# #+# */
-/* Updated: 2026/05/04 01:17:51 by agilliar ### ########.fr */
+/* Updated: 2026/05/05 20:54:09 by agilliar ### ########.fr */
/* */
/* ************************************************************************** */
i = 0;
while (i < list->len)
- value_destroy(list->list[i++]);
+ value_destroy(&list->list[i++]);
}
-void value_destroy(t_value value)
+void value_destroy(t_value *value)
{
- value_drop_arc(&value, (t_unpack) value_builtin_get, noop);
- value_drop_arc(&value, (t_unpack) value_list_get, (t_drop) value_list_del);
- value_drop_arc(&value, (t_unpack) value_bytes_get, noop);
+ value_drop_arc(value, (t_unpack) value_builtin_get, noop);
+ value_drop_arc(value, (t_unpack) value_list_get, (t_drop) value_list_del);
+ value_drop_arc(value, (t_unpack) value_bytes_get, noop);
+ *value = value_undefined_new();
}
/* By: agilliar <agilliar@student.42mulhouse.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/04/30 17:27:40 by agilliar #+# #+# */
-/* Updated: 2026/05/04 01:18:03 by agilliar ### ########.fr */
+/* Updated: 2026/05/05 21:32:17 by agilliar ### ########.fr */
/* */
/* ************************************************************************** */
if ((value.discrim & VALUE_MASK) != VALUE_PTR)
return (NULL);
res = value.ptr - offsetof(struct s_value_builtin, builtin);
- if (res->discrim != VALUE_PTR_BUILTIN)
+ if (!value.ptr || res->discrim != VALUE_PTR_BUILTIN)
return (NULL);
return (res);
}
if ((value.discrim & VALUE_MASK) != VALUE_PTR)
return (NULL);
res = value.ptr - offsetof(struct s_value_list, list);
- if (res->discrim != VALUE_PTR_LIST)
+ if (!value.ptr || res->discrim != VALUE_PTR_LIST)
return (NULL);
return (res);
}
if ((value.discrim & VALUE_MASK) != VALUE_PTR)
return (NULL);
res = value.ptr - offsetof(struct s_value_bytes, bytes);
- if (res->discrim != VALUE_PTR_BYTES)
+ if (!value.ptr || res->discrim != VALUE_PTR_BYTES)
return (NULL);
return (res);
}
/* By: agilliar <agilliar@student.42mulhouse.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/05/04 02:05:48 by agilliar #+# #+# */
-/* Updated: 2026/05/04 03:27:11 by agilliar ### ########.fr */
+/* Updated: 2026/05/05 20:37:17 by agilliar ### ########.fr */
/* */
/* ************************************************************************** */
new_list->list[i] = value_copy(list->list[i]);
i++;
}
- value_destroy(*value);
+ value_destroy(value);
*value = new;
return (new_list);
}
if (!new_bytes)
return (NULL);
memcpy(new_bytes->bytes, bytes->bytes, bytes->len);
- value_destroy(*value);
+ value_destroy(value);
*value = new;
return (new_bytes);
}
/* By: agilliar <agilliar@student.42mulhouse.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/04/30 16:25:42 by agilliar #+# #+# */
-/* Updated: 2026/05/04 01:49:28 by agilliar ### ########.fr */
+/* Updated: 2026/05/05 21:25:48 by agilliar ### ########.fr */
/* */
/* ************************************************************************** */
t_value res_raw;
res = arc_create(sizeof(struct s_value_builtin));
- if (!res)
- return (value_undefined_new());
res->discrim = VALUE_PTR_BUILTIN;
res->builtin = builtin;
res_raw.ptr = &res->builtin;
t_usize n;
if (__builtin_mul_overflow(len, sizeof(t_value), &n)
- || __builtin_add_overflow(n, sizeof(struct s_value_list), &n))
- return (value_undefined_new());
+ || __builtin_add_overflow(n, sizeof(t_value_list), &n))
+ panic("List size overflowed");
res = arc_create(n);
- if (!res)
- return (value_undefined_new());
res->discrim = VALUE_PTR_LIST;
res->len = len;
n = 0;
t_usize n;
if (__builtin_add_overflow(len, sizeof(struct s_value_bytes), &n))
- return (value_undefined_new());
+ panic("Bytes size overflowed");
res = arc_create(n);
- if (!res)
- return (value_undefined_new());
res->discrim = VALUE_PTR_BYTES;
res->len = len;
memset(&res->bytes, 0, len);
--- /dev/null
+/* ************************************************************************** */
+/* */
+/* ::: :::::::: */
+/* value_readf.c :+: :+: :+: */
+/* +:+ +:+ +:+ */
+/* By: agilliar <agilliar@student.42mulhouse.fr> +#+ +:+ +#+ */
+/* +#+#+#+#+#+ +#+ */
+/* Created: 2026/05/05 15:21:41 by agilliar #+# #+# */
+/* Updated: 2026/05/05 16:58:28 by agilliar ### ########.fr */
+/* */
+/* ************************************************************************** */
+
+#include "ccera.h"
+
+// i: int
+// (: list
+// ): end list
+// .: list rem discard
+// _: skip
+// b: bytes
+// l: list
+// v: value
+// value_readf("((li)v)")
+//bool value_readf(const char *f, void **out, bool move)
+//{
+//}
/* By: agilliar <agilliar@student.42mulhouse.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/04/30 17:19:58 by agilliar #+# #+# */
-/* Updated: 2026/05/04 04:13:07 by agilliar ### ########.fr */
+/* Updated: 2026/05/06 02:32:34 by agilliar ### ########.fr */
/* */
/* ************************************************************************** */
#include <string.h>
#include <stdio.h>
-int main(void)
+void main2(void *s)
{
- char *s = "Hello cera!";
+ t_defer defer_store __attribute__((cleanup(defer_exit)));
+ defer_new(&defer_store);
+
t_value arg = value_bytes_new(strlen(s) + 1);
+ defer(value_destroy, &arg);
+ //panic("A");
t_value state = value_list_new(0);
+ defer(value_destroy, &state);
+ //panic("B");
t_value idx = value_int_new(0);
t_value fn = value_list_new(2);
+ defer(value_destroy, &fn);
+ //panic("C");
t_value expr = value_list_new(2);
+ defer(value_destroy, &expr);
+ //panic("D");
+ defer_re(&defer_store);
value_list_get(fn)->list[0] = state;
value_list_get(fn)->list[1] = idx;
value_list_get(expr)->list[0] = fn;
value_list_get(expr)->list[1] = arg;
+ defer(value_destroy, &expr);
+ //panic("E");
t_value val = value_copy(expr);
- printf("%p\n", expr_eval(expr).ptr);
- value_destroy(val);
+ defer(value_destroy, &val);
+ //panic("F");
+}
+
+int main(void)
+{
+ if (char *err = catch(main2, "Hello cera!"))
+ {
+ printf("%s\n", err);
+ return (1);
+ }
}