about summary refs log tree commit diff
path: root/val.c
diff options
context:
space:
mode:
Diffstat (limited to 'val.c')
-rw-r--r--val.c144
1 files changed, 144 insertions, 0 deletions
diff --git a/val.c b/val.c
new file mode 100644
index 0000000..b8dc30d
--- /dev/null
+++ b/val.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2026 Nakidai Perumenei <nakidai at disroot dot org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "thac.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+
+struct val
+deref(struct val val, struct scope *scope)
+{
+	long i;
+
+	if (val.type == VVAR)
+	{
+		i = findvar(val.name, &scope);
+		if (i < 0)
+			complain(1, "no such variable: %s", val.name);
+		val = scope->vars[i].val;
+	}
+
+	return val;
+}
+
+struct val
+getval(enum val_t t, struct val val, struct scope *scope, int doderef)
+{
+	if (doderef)
+		val = deref(val, scope);
+	if (val.type != t)
+		complain(1, "expected %s, got %s", valname(t), valname(val.type));
+	return val;
+}
+
+struct val
+copyval(struct val old)
+{
+	struct val new;
+	ulong i;
+
+	new = old;
+	if (new.type == VARR)
+	{
+		new.arr = malloc(sizeof(*new.arr) * new.len);
+		if (!new.arr)
+			dieno(1, "malloc()");
+
+		for (i = 0; i < new.len; ++i)
+			new.arr[i] = copyval(old.arr[i]);
+	}
+
+	return new;
+}
+
+void
+freeval(struct val val)
+{
+	ulong i;
+
+	if (val.type == VARR)
+	{
+		for (i = 0; i < val.len; ++i)
+			freeval(val.arr[i]);
+		free(val.arr);
+	}
+}
+
+static void
+connectarr(struct val arr, ulong single, int arr_to_single)
+{
+	ulong i;
+
+	for (i = 0; i < arr.len; ++i) switch (arr.arr[i].type)
+	{
+	break; case VARR:
+		connectarr(arr.arr[i], single, arr_to_single);
+	break; case VNUM:
+		if (arr_to_single)
+			addedge(arr.arr[i].num, single);
+		else
+			addedge(single, arr.arr[i].num);
+	break; default: complain(1, "%s can not be connected", valname(arr.arr[i].type));
+	}
+}
+
+static void
+connectarrarr(struct val from, struct val to)
+{
+	ulong i;
+
+	if (from.len != to.len)
+		complain(1, "cannot connect nonisomorphic arrays");
+
+	for (i = 0; i < from.len; ++i)
+	{
+		if (from.arr[i].type != to.arr[i].type)
+			complain(1, "cannot connect nonisomorphic arrays");
+		switch (from.arr[i].type)
+		{
+		break; case VARR: connectarrarr(from.arr[i], to.arr[i]);
+		break; case VNUM: addedge(from.arr[i].num, to.arr[i].num);
+		break; default: complain(1, "%s can not be connected", valname(from.arr[i].type));
+		}
+	}
+}
+
+struct val
+connectval(struct val refl, struct val refr, struct scope *scope)
+{
+	struct val l, r;
+
+	l = deref(refl, scope);
+	r = deref(refr, scope);
+
+	if (l.type == VNUM && r.type == VNUM)
+		addedge(r.num, l.num);
+	else if (l.type == VARR && r.type == VNUM)
+		connectarr(l, r.num, 0);
+	else if (l.type == VNUM && r.type == VARR)
+		connectarr(r, l.num, 1);
+	else if (l.type == VARR && r.type == VARR)
+		connectarrarr(r, l);
+	else
+		complain(1, "cannot connect %s and %s", valname(l.type), valname(r.type));
+
+	if (refr.type != VVAR)
+		freeval(r);
+
+	return refl;
+}