${BUILDDIR}/arc.o: src/arc.c src/arc.h src/memutils.h src/panic.h src/jmp.h \
src/arith.h src/atomic.h
+${BUILDDIR}/builtin_noop.o: src/builtin_noop.c src/memutils.h src/panic.h src/jmp.h \
+ src/value.h src/value_get.h src/value_types.h src/value_new.h \
+ src/arc.h src/arith.h
${BUILDDIR}/defer.o: src/defer.c src/defer.h src/framealloc.h src/align.h \
src/stacktrack.h src/memutils.h src/panic.h src/jmp.h
${BUILDDIR}/eval.o: src/eval.c src/ccera.h src/jmp.h src/defer.h src/framealloc.h \
NAME=ccera.a
-SRCS=src/arc.c src/defer.c src/eval.c src/framealloc.c src/panic.c src/stacktrack.c src/value_lifetime.c src/value_list.c src/value_move.c src/value_new.c
+SRCS=src/arc.c src/builtin_noop.c src/defer.c src/eval.c src/framealloc.c src/panic.c src/stacktrack.c src/value_lifetime.c src/value_list.c src/value_move.c src/value_new.c
HEADERS=src/align.h src/arc.h src/arith.h src/atomic.h src/ccera.h src/defer.h src/framealloc.h src/jmp.h src/memutils.h src/panic.h src/stacktrack.h src/value_get.h src/value.h src/value_new.h src/value_types.h
-#LTO=1
-CC=gcc
+LTO=1
+#CC=gcc
#UBSAN=1
-TSAN=1
+#TSAN=1
#ASAN=1
/* By: agilliar <agilliar@student.42mulhouse.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/05/13 08:56:53 by agilliar #+# #+# */
-/* Updated: 2026/05/14 15:55:35 by agilliar ### ########.fr */
+/* Updated: 2026/05/18 14:43:36 by agilliar ### ########.fr */
/* */
/* ************************************************************************** */
/* By: agilliar <agilliar@student.42mulhouse.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/05/15 11:18:31 by agilliar #+# #+# */
-/* Updated: 2026/05/15 11:23:58 by agilliar ### ########.fr */
+/* Updated: 2026/05/18 13:11:57 by agilliar ### ########.fr */
/* */
/* ************************************************************************** */
# include <stddef.h>
-# if __has_feature(thread_sanitizer)
+# ifdef __SANITIZE_THREAD__
__attribute__((always_inline))
static inline void acquire_fence_on(size_t *p)
--- /dev/null
+/* ************************************************************************** */
+/* */
+/* ::: :::::::: */
+/* builtin_noop.c :+: :+: :+: */
+/* +:+ +:+ +:+ */
+/* By: agilliar <agilliar@student.42mulhouse.fr> +#+ +:+ +#+ */
+/* +#+#+#+#+#+ +#+ */
+/* Created: 2026/05/18 14:35:11 by agilliar #+# #+# */
+/* Updated: 2026/05/18 15:01:29 by agilliar ### ########.fr */
+/* */
+/* ************************************************************************** */
+
+#include "memutils.h"
+#include "value.h"
+#include "arc.h"
+
+#include <stdio.h>
+
+static t_value builtin_noop_impl(t_value self, t_value val)
+{
+ value_drop(&self);
+ printf("In noop!\n");
+ return (val);
+}
+
+t_value builtin_noop(void)
+{
+ return (value_new_builtin(&builtin_noop_impl, &noop, 0));
+}
/* By: agilliar <agilliar@student.42mulhouse.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/04/29 16:08:57 by agilliar #+# #+# */
-/* Updated: 2026/05/15 11:21:51 by agilliar ### ########.fr */
+/* Updated: 2026/05/18 14:47:29 by agilliar ### ########.fr */
/* */
/* ************************************************************************** */
// move is whether said value shall be moved out
//
// This function takes ownership
-t_value expr_eval(t_value expr);
+t_value expr_eval(t_value eval, t_value arg);
+t_value builtin_noop(void);
#endif
/* By: agilliar <agilliar@student.42mulhouse.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/05/04 01:21:34 by agilliar #+# #+# */
-/* Updated: 2026/05/14 14:58:19 by agilliar ### ########.fr */
+/* Updated: 2026/05/18 15:00:10 by agilliar ### ########.fr */
/* */
/* ************************************************************************** */
#include "ccera.h"
-// Has ownership of the values given
-t_value eval_step(t_value arg, t_value *exprs, uintptr_t *i)
+void step_extract(t_value *exprs, uintptr_t *i, t_value *eval, t_value *arg)
{
- (void) arg;
- (void) exprs;
- (void) i;
- return (value_new_nil());
+ uintptr_t pos;
+ uintptr_t mov;
+
+ pos = *value_uint(value_list_get(*value_list_get(*exprs, *i), 0));
+ mov = *value_uint(value_list_get(*value_list_get(*exprs, *i), 1));
+ if (mov)
+ value_swap(value_list_getu(exprs, pos), eval);
+ else
+ value_put(eval, value_copy(*value_list_getu(exprs, pos)));
+ pos = *value_uint(value_list_get(*value_list_get(*exprs, *i), 2));
+ mov = *value_uint(value_list_get(*value_list_get(*exprs, *i), 3));
+ if (mov)
+ value_swap(value_list_getu(exprs, pos), arg);
+ else
+ value_put(arg, value_copy(*value_list_getu(exprs, pos)));
+}
+
+void compound_eval(t_value *eval, t_value *arg)
+{
+ t_value *exprs;
+ uintptr_t *i;
+ t_value step_eval;
+ t_value step_arg;
+
+ step_eval = value_new_nil();
+ defer(value_drop, &step_eval);
+ step_arg = value_new_nil();
+ defer(value_drop, &step_arg);
+ exprs = value_list_getu(eval, 0);
+ i = value_uint(value_list_getu(eval, 1));
+ value_swap(value_list_getu(exprs, (*i)++), arg);
+ step_extract(exprs, i, &step_eval, &step_arg);
+ if (value_list_len(*exprs) + 1 == *i)
+ return (value_swap(eval, &step_eval), value_swap(arg, &step_arg));
+ value_put(arg, expr_eval(
+ value_take_nil(&step_eval), value_take_nil(&step_arg)));
+}
+
+void builtin_eval(t_value eval, t_value *arg)
+{
+ value_put(arg, value_builtin(&eval)->f(eval, value_take_nil(arg)));
}
-// The expression value is a tuple of an evaluatable and the argument to give it
-//
// Value-evaluatables are laid out as follows:
// (
// ((values | nil)* .. (exprs | nil)*),
// The nil expressions are locations where an argument is expected, halting
// evaluation
// An expression is as follows:
-// (eval_idx, arg_idx, move)
+// (eval_idx, eval_move, arg_idx, arg_move)
// eval_idx is the index of the function to be evaluated
// arg_idx is the index of the argument to said function
// move is whether said value shall be moved out
//
// This function takes ownership
-t_value expr_eval(t_value expr)
+t_value expr_eval(t_value eval, t_value arg)
{
- t_value *eval;
- t_value arg;
- t_value *exprs;
- uintptr_t *i;
-
- defer(value_drop, &expr);
- eval = value_list_getu(&expr, 0);
- arg = value_take_nil(value_list_getu(&expr, 1));
- exprs = value_list_getu(eval, 0);
- i = value_uint(value_list_getu(eval, 1));
- (void) exprs;
- (void) i;
- while (*i < value_list(exprs)->len)
+ defer(value_drop, &eval);
+ errdefer(value_drop, &arg);
+ while (true)
{
- eval_step(arg, exprs, i);
- (*i)++;
+ if (eval.tag == VALUE_BUILTIN)
+ {
+ return (builtin_eval(value_take_nil(&eval), &arg), arg);
+ }
+ else if (eval.tag == VALUE_LIST)
+ compound_eval(&eval, &arg);
+ else
+ panic("Invalid type for evaluatable");
}
- return (value_take_nil(value_list_getu(eval, (*i) - 1)));
}
/* By: agilliar <agilliar@student.42mulhouse.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/05/05 15:38:33 by agilliar #+# #+# */
-/* Updated: 2026/05/15 11:04:14 by agilliar ### ########.fr */
+/* Updated: 2026/05/18 15:36:28 by agilliar ### ########.fr */
/* */
/* ************************************************************************** */
return (&store);
}
+// Scuffed but clang is adament on not doing proper analysis on the semantics
+// of setjmp/longjmp
+__attribute__((noinline))
+static t_panic_info *panic_store2(void)
+{
+ return (panic_store());
+}
+
void *catch(void *f, void *dat)
{
void *res;
panic_store()->stacktrack_pos = stacktrack_pos();
if (__builtin_setjmp((void *)&panic_store()->jmp))
{
- res = panic_store()->data;
- *panic_store() = prev;
+ res = panic_store2()->data;
+ *panic_store2() = prev;
return (res);
}
((void (*)(void *))f)(dat);
/* By: agilliar <agilliar@student.42mulhouse.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/05/12 16:14:16 by agilliar #+# #+# */
-/* Updated: 2026/05/13 22:20:49 by agilliar ### ########.fr */
+/* Updated: 2026/05/18 12:48:22 by agilliar ### ########.fr */
/* */
/* ************************************************************************** */
void value_drop(t_value *value);
t_value value_unique(t_value *val);
+size_t value_list_len(t_value lst);
t_value *value_list_get(t_value lst, size_t i);
t_value *value_list_getu(t_value *lst, size_t i);
void value_swap(t_value *a, t_value *b);
t_value value_take(t_value *a, t_value b);
t_value value_take_nil(t_value *a);
+void value_put(t_value *a, t_value b);
#endif
/* By: agilliar <agilliar@student.42mulhouse.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/05/13 22:01:24 by agilliar #+# #+# */
-/* Updated: 2026/05/13 22:29:29 by agilliar ### ########.fr */
+/* Updated: 2026/05/18 14:49:16 by agilliar ### ########.fr */
/* */
/* ************************************************************************** */
return (value->val.v_bytes);
}
+__attribute__((always_inline))
+static inline t_builtin *value_builtin(t_value *value)
+{
+ if (value->tag != VALUE_BUILTIN)
+ panic("Expected value to be builtin");
+ return (value->val.v_builtin);
+}
+
#endif
/* By: agilliar <agilliar@student.42mulhouse.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/05/12 17:42:10 by agilliar #+# #+# */
-/* Updated: 2026/05/13 22:29:20 by agilliar ### ########.fr */
+/* Updated: 2026/05/18 14:34:35 by agilliar ### ########.fr */
/* */
/* ************************************************************************** */
arc_copy(val.val.v_bytes);
else if (val.tag == VALUE_LIST)
arc_copy(val.val.v_list);
+ else if (val.tag == VALUE_BUILTIN)
+ arc_copy(val.val.v_builtin);
return (val);
}
lst->len++;
}
}
- return (res);
+ return (value_copy(res));
}
static void list_drop(t_list *lst)
void value_drop(t_value *value)
{
- if (value->tag == VALUE_BYTES)
- arc_drop(value->val.v_bytes, noop);
- else if (value->tag == VALUE_BYTES)
+ if (value->tag == VALUE_LIST)
arc_drop(value->val.v_list, list_drop);
+ else if (value->tag == VALUE_BUILTIN)
+ arc_drop(value->val.v_builtin, value->val.v_builtin->drop);
+ else if (value->tag == VALUE_BYTES)
+ arc_drop(value->val.v_bytes, noop);
}
t_value value_unique(t_value *val)
/* By: agilliar <agilliar@student.42mulhouse.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/05/13 12:51:13 by agilliar #+# #+# */
-/* Updated: 2026/05/13 22:30:13 by agilliar ### ########.fr */
+/* Updated: 2026/05/18 12:47:53 by agilliar ### ########.fr */
/* */
/* ************************************************************************** */
#include "value.h"
#include "panic.h"
-// Borrows the value
-t_value *value_list_get(t_value lst, size_t i)
+size_t value_list_len(t_value lst)
{
if (lst.tag != VALUE_LIST)
panic("List get on wrong type");
- if (lst.val.v_list->len <= i)
+ return (lst.val.v_list->len);
+}
+
+// Borrows the value
+t_value *value_list_get(t_value lst, size_t i)
+{
+ if (value_list_len(lst) <= i)
panic("List get out of bounds");
return (&lst.val.v_list->buf[i]);
}
/* By: agilliar <agilliar@student.42mulhouse.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/05/13 21:27:54 by agilliar #+# #+# */
-/* Updated: 2026/05/13 22:30:27 by agilliar ### ########.fr */
+/* Updated: 2026/05/18 11:55:04 by agilliar ### ########.fr */
/* */
/* ************************************************************************** */
{
return (value_take(a, value_new_nil()));
}
+
+void value_put(t_value *a, t_value b)
+{
+ value_swap(a, &b);
+ value_drop(&b);
+}
/* By: agilliar <agilliar@student.42mulhouse.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/05/13 08:40:13 by agilliar #+# #+# */
-/* Updated: 2026/05/13 18:17:10 by agilliar ### ########.fr */
+/* Updated: 2026/05/18 14:56:45 by agilliar ### ########.fr */
/* */
/* ************************************************************************** */
return (res);
}
+// We could use arc_new_zeroed but clang and gcc cannot tell that the
+// following zero writes for the nil values are no-ops
t_value value_new_list(size_t len)
{
t_value res;
size_t i;
res.tag = VALUE_LIST;
- res.val.v_list = arc_new_zeroed(
+ res.val.v_list = arc_new(
uadd(sizeof(t_list), umul(sizeof(t_value), len)));
res.val.v_list->len = len;
i = 0;
res.val.v_list->buf[i++] = value_new_nil();
return (res);
}
+
+t_value value_new_builtin(t_value (*f)(t_value, t_value),
+ void *drop, size_t len)
+{
+ t_value res;
+
+ res.tag = VALUE_BUILTIN;
+ res.val.v_list = arc_new(
+ uadd(sizeof(t_builtin), len));
+ res.val.v_builtin->f = f;
+ res.val.v_builtin->drop = drop;
+ return (res);
+}
/* By: agilliar <agilliar@student.42mulhouse.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/05/13 22:05:40 by agilliar #+# #+# */
-/* Updated: 2026/05/13 22:06:22 by agilliar ### ########.fr */
+/* Updated: 2026/05/18 14:57:37 by agilliar ### ########.fr */
/* */
/* ************************************************************************** */
t_value value_new_bytes(size_t len);
t_value value_new_str(const char *s);
t_value value_new_list(size_t len);
+t_value value_new_builtin(t_value (*f)(t_value, t_value),
+ void *drop, size_t len);
#endif
/* By: agilliar <agilliar@student.42mulhouse.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/05/13 22:04:36 by agilliar #+# #+# */
-/* Updated: 2026/05/15 13:05:11 by agilliar ### ########.fr */
+/* Updated: 2026/05/18 14:57:06 by agilliar ### ########.fr */
/* */
/* ************************************************************************** */
#ifndef VALUE_TYPES_H
# define VALUE_TYPES_H
-typedef struct s_bytes t_bytes;
-typedef struct s_list t_list;
+typedef struct s_bytes t_bytes;
+typedef struct s_list t_list;
+typedef struct s_builtin t_builtin;
union u_value
{
intptr_t v_int;
t_bytes *v_bytes;
t_list *v_list;
+ t_builtin *v_builtin;
};
enum e_value: uint8_t
VALUE_UINT,
VALUE_BYTES,
VALUE_LIST,
+ VALUE_BUILTIN,
};
typedef struct s_value
t_value buf[];
};
+// F: self, arg -> res
+struct s_builtin
+{
+ t_value (*f)(t_value, t_value);
+ void (*drop)(t_builtin *);
+ char buf[];
+};
+
#endif
/* By: agilliar <agilliar@student.42mulhouse.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/04/30 17:19:58 by agilliar #+# #+# */
-/* Updated: 2026/05/15 11:08:09 by agilliar ### ########.fr */
+/* Updated: 2026/05/18 15:03:08 by agilliar ### ########.fr */
/* */
/* ************************************************************************** */
char *s2 = malloc(strlen(orig) + 1);
defer(free, s2);
strcpy(s2, orig);
+ t_value res = expr_eval(builtin_noop(), value_new_uint(7));
+ defer(value_drop, &res);
printf("%s\n", s2);
panic("error!");
printf("%s\n", s2);