diff --git a/Makefile b/Makefile
index be99669..fafcfe8 100644
--- a/Makefile
+++ b/Makefile
@@ -16,6 +16,7 @@ build:
${MAKE} -C ucd2c build
${MAKE} -C libc3 build
${MAKE} -C ic3 build
+ ${MAKE} -C c3s build
${MAKE} -C test build
all:
@@ -23,18 +24,21 @@ all:
${MAKE} -C ucd2c all
${MAKE} -C libc3 all
${MAKE} -C ic3 all
+ ${MAKE} -C c3s all
${MAKE} -C test all
asan:
${MAKE} -C libtommath asan
${MAKE} -C libc3 asan
${MAKE} -C ic3 asan
+ ${MAKE} -C c3s asan
${MAKE} -C test asan
cov:
${MAKE} -C libtommath cov
${MAKE} -C libc3 cov
${MAKE} -C ic3 cov
+ ${MAKE} -C c3s cov
${MAKE} -C test cov
clean:
@@ -42,18 +46,21 @@ clean:
${MAKE} -C ucd2c clean
${MAKE} -C libc3 clean
${MAKE} -C ic3 clean
+ ${MAKE} -C c3s clean
${MAKE} -C test clean
clean_cov:
${MAKE} -C libtommath clean_cov
${MAKE} -C libc3 clean_cov
${MAKE} -C ic3 clean_cov
+ ${MAKE} -C c3s clean_cov
${MAKE} -C test clean_cov
debug:
${MAKE} -C libtommath debug
${MAKE} -C libc3 debug
${MAKE} -C ic3 debug
+ ${MAKE} -C c3s debug
${MAKE} -C test debug
dist: c3-${C3_VERSION}.tar.gz
@@ -68,11 +75,13 @@ distclean:
${MAKE} -C ucd2c distclean
${MAKE} -C libc3 distclean
${MAKE} -C ic3 distclean
+ ${MAKE} -C c3s distclean
${MAKE} -C test distclean
gcovr:
${MAKE} -C libc3 gcovr
${MAKE} -C ic3 gcovr
+ ${MAKE} -C c3s gcovr
${MAKE} -C test gcovr
if [ -d "$$HOME/Downloads/c3_gcovr" ]; then bin/gcovr-to-downloads; fi
@@ -93,6 +102,7 @@ ic3_test_cov: cov
install: all
${MAKE} -C libc3 install
${MAKE} -C ic3 install
+ ${MAKE} -C c3s install
libc3_gcovr:
${MAKE} clean_cov
@@ -128,6 +138,6 @@ test_gcovr:
test_ic3: build
${MAKE} -C test test_ic3
-.PHONY: all asan cov clean clean_cov debug gcovr ic3 install libc3 libtommath license test test_asan test_cov test_debug test_gcovr test_ic3
+.PHONY: all asan c3s cov clean clean_cov debug gcovr ic3 install libc3 libtommath license test test_asan test_cov test_debug test_gcovr test_ic3
include config.mk
diff --git a/c3s/Makefile b/c3s/Makefile
new file mode 100644
index 0000000..fee6dd0
--- /dev/null
+++ b/c3s/Makefile
@@ -0,0 +1,49 @@
+## c3
+## Copyright 2022 kmx.io <contact@kmx.io>
+##
+## Permission is hereby granted to use this software granted
+## the above copyright notice and this permission paragraph
+## are included in all copies and substantial portions of this
+## software.
+##
+## THIS SOFTWARE IS PROVIDED "AS-IS" WITHOUT ANY GUARANTEE OF
+## PURPOSE AND PERFORMANCE. IN NO EVENT WHATSOEVER SHALL THE
+## AUTHOR BE CONSIDERED LIABLE FOR THE USE AND PERFORMANCE OF
+## THIS SOFTWARE.
+
+CLEANFILES = *.a c3s c3s.asan c3s.cov c3s.debug *.css *.gcno *.html *.o .libs *.lo
+
+CLEANFILES_COV = *.css *.gcda *.html .libs/*.gcda
+CLEANFILES += ${CLEANFILES_COV}
+
+DISTCLEANFILES = ${CLEANFILES} config.mk
+
+build: c3s
+
+all: build cov debug
+ if ${HAVE_ASAN}; then ${MAKE} asan; fi
+
+asan: c3s.asan
+
+clean:
+ rm -rf ${CLEANFILES}
+
+clean_cov:
+ rm -rf ${CLEANFILES_COV}
+
+cov: c3s.cov
+
+debug: c3s.debug
+
+distclean:
+ rm -rf ${DISTCLEANFILES}
+
+gcovr:
+ gcovr --gcov-executable ${GCOV} --html-details c3s.html
+
+gdb_c3s: debug
+ if [ -f c3s.debug.core ]; then gdb c3s.debug c3s.debug.core; else gdb c3s.debug; fi
+
+.PHONY: all asan cov debug clean clean_cov distclean
+
+include config.mk
diff --git a/c3s/buf_readline.c b/c3s/buf_readline.c
new file mode 120000
index 0000000..1bb7fb6
--- /dev/null
+++ b/c3s/buf_readline.c
@@ -0,0 +1 @@
+../ic3/buf_readline.c
\ No newline at end of file
diff --git a/c3s/buf_readline.h b/c3s/buf_readline.h
new file mode 120000
index 0000000..5682b51
--- /dev/null
+++ b/c3s/buf_readline.h
@@ -0,0 +1 @@
+../ic3/buf_readline.h
\ No newline at end of file
diff --git a/c3s/c3s b/c3s/c3s
new file mode 100755
index 0000000..388be99
Binary files /dev/null and b/c3s/c3s differ
diff --git a/c3s/c3s.c b/c3s/c3s.c
new file mode 100644
index 0000000..cebd0d3
--- /dev/null
+++ b/c3s/c3s.c
@@ -0,0 +1,119 @@
+/* c3
+ * Copyright 2022 kmx.io <contact@kmx.io>
+ *
+ * Permission is hereby granted to use this software granted
+ * the above copyright notice and this permission paragraph
+ * are included in all copies and substantial portions of this
+ * software.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS-IS" WITHOUT ANY GUARANTEE OF
+ * PURPOSE AND PERFORMANCE. IN NO EVENT WHATSOEVER SHALL THE
+ * AUTHOR BE CONSIDERED LIABLE FOR THE USE AND PERFORMANCE OF
+ * THIS SOFTWARE.
+ */
+#include "../libc3/c3.h"
+#include "buf_readline.h"
+
+#define BUFSZ 0x10000
+
+int usage (char *argv0);
+
+sw buf_ignore_character (s_buf *buf)
+{
+ u8 b;
+ character c = 0;
+ sw csize;
+ sw r;
+ if ((r = buf_peek_character_utf8(buf, &c)) > 0)
+ csize = r;
+ else if ((r = buf_peek_u8(buf, &b)) > 0)
+ csize = 1;
+ else
+ return r;
+ if ((r = buf_ignore(buf, csize)) < 0)
+ return r;
+ return csize;
+}
+
+sw buf_xfer_spaces (s_buf *out, s_buf *in)
+{
+ character c;
+ sw csize;
+ sw r;
+ sw size = 0;
+ assert(in);
+ assert(out);
+ while ((r = buf_peek_character_utf8(in, &c)) > 0 &&
+ c >= 0 &&
+ c < UCD_MAX &&
+ g_ucd[c].flags & (UCD_OTHER_CONTROL | UCD_SEPARATOR_SPACE)) {
+ csize = r;
+ if ((r = buf_xfer(out, in, csize)) != csize)
+ return -1;
+ size += csize;
+ if ((r = buf_flush(out)) < 0)
+ return -1;
+ }
+ if (r < 0)
+ return r;
+ return size;
+}
+
+int main (int argc, char **argv)
+{
+ s_module c3;
+ s_env env;
+ s_facts facts;
+ s_buf in;
+ s_tag input;
+ s_buf out;
+ sw r;
+ s_tag result;
+ libc3_init();
+ facts_init(&facts, NULL);
+ c3_init(&c3, &facts);
+ if (argc < 1)
+ return usage(argv[0]);
+ BUF_INIT_ALLOCA(&in, BUFSZ);
+ buf_file_open_r(&in, stdin);
+ BUF_INIT_ALLOCA(&out, BUFSZ);
+ buf_file_open_w(&out, stdout);
+ env_init(&env);
+ while ((r = buf_xfer_spaces(&out, &in)) >= 0) {
+ if ((r = buf_parse_tag(&in, &input)) > 0) {
+ if (! eval_tag(&env, &result, &input)) {
+ tag_clean(&input);
+ continue;
+ }
+ if (buf_inspect_tag(&out, &result) < 0) {
+ tag_clean(&input);
+ tag_clean(&result);
+ break;
+ }
+ tag_clean(&input);
+ tag_clean(&result);
+ buf_write_u8(&out, '\n');
+ if ((r = buf_flush(&out)) < 0)
+ break;
+ }
+ if (r < 0 ||
+ (r == 0 &&
+ (r = buf_ignore_character(&in)) <= 0))
+ break;
+ if ((r = buf_refill_compact(&in)) < 0)
+ break;
+ }
+ env_clean(&env);
+ buf_readline_close(&in);
+ buf_file_close(&out);
+ c3_clean(&c3);
+ facts_clean(&facts);
+ libc3_shutdown();
+ return 0;
+}
+
+int usage (char *argv0)
+{
+ printf("Usage: %s\n", argv0);
+ return 1;
+}
diff --git a/c3s/c3s.cov b/c3s/c3s.cov
new file mode 100755
index 0000000..4811e8c
Binary files /dev/null and b/c3s/c3s.cov differ
diff --git a/c3s/configure b/c3s/configure
new file mode 100755
index 0000000..7861d01
--- /dev/null
+++ b/c3s/configure
@@ -0,0 +1,133 @@
+#!/bin/sh
+## c3
+## Copyright 2022 kmx.io <contact@kmx.io>
+##
+## Permission is hereby granted to use this software granted
+## the above copyright notice and this permission paragraph
+## are included in all copies and substantial portions of this
+## software.
+##
+## THIS SOFTWARE IS PROVIDED "AS-IS" WITHOUT ANY GUARANTEE OF
+## PURPOSE AND PERFORMANCE. IN NO EVENT WHATSOEVER SHALL THE
+## AUTHOR BE CONSIDERED LIABLE FOR THE USE AND PERFORMANCE OF
+## THIS SOFTWARE.
+
+set -e
+
+. ../config.subr
+
+PROG=c3s
+PROG_ASAN=c3s.asan
+PROG_COV=c3s.cov
+PROG_DEBUG=c3s.debug
+
+SOURCES="$(ls *.c | tr '\n' ' ')"
+echo "SOURCES = $SOURCES" >> ${CONFIG_MK}
+
+OBJECTS="$(c2lo "$SOURCES")"
+echo "OBJECTS = $OBJECTS" >> ${CONFIG_MK}
+
+OBJECTS_ASAN="$(c2ext .asan.lo "$SOURCES")"
+echo "OBJECTS_ASAN = $OBJECTS_ASAN" >> ${CONFIG_MK}
+
+OBJECTS_COV="$(c2ext .cov.lo "$SOURCES")"
+echo "OBJECTS_COV = $OBJECTS_COV" >> ${CONFIG_MK}
+
+OBJECTS_DEBUG="$(c2ext .debug.lo "$SOURCES")"
+echo "OBJECTS_DEBUG = $OBJECTS_DEBUG" >> ${CONFIG_MK}
+
+# Default config
+CPPFLAGS="${CPPFLAGS:=}"
+ENV_CFLAGS="${CFLAGS:=}"
+DEFAULT_CFLAGS="-O2 -pipe -fPIC"
+LDFLAGS="${LDFLAGS:=}"
+LIBS="${LIBS:=-lm -lreadline -lffi}"
+
+# Common config for all targets
+CFLAGS="$CFLAGS -W -Wall -Werror -std=c99 -pedantic"
+config_asan
+config_libbsd
+
+# Asan config
+CFLAGS_ASAN="$CFLAGS -fsanitize=address -O1 -fno-omit-frame-pointer -g"
+LDFLAGS_ASAN="$LDFLAGS"
+LIBC3_ASAN=../libc3/libc3.asan.a
+LIBS_ASAN="$LIBC3_ASAN $LIBS"
+
+# Coverage config
+CFLAGS_COV="$CFLAGS -ftest-coverage -fprofile-arcs"
+LDFLAGS_COV="$LDFLAGS"
+LIBC3_COV=../libc3/libc3.cov.a
+LIBS_COV="$LIBC3_COV $LIBS"
+
+# Debug config
+CFLAGS_DEBUG="$CFLAGS -DDEBUG -O0 -ggdb"
+LDFLAGS_DEBUG="$LDFLAGS"
+LIBC3_DEBUG=../libc3/libc3.debug.a
+LIBS_DEBUG="$LIBC3_DEBUG $LIBS"
+
+# Main config
+if [ "x$ENV_CFLAGS" = "x" ]; then
+ CFLAGS="$CFLAGS $DEFAULT_CFLAGS"
+fi
+CFLAGS="$CFLAGS -DNDEBUG"
+LIBC3=../libc3/libc3.a
+LIBS="$LIBC3 $LIBS"
+
+echo "HAVE_ASAN = $HAVE_ASAN" >> ${CONFIG_MK}
+echo "CPPFLAGS = $CPPFLAGS" >> ${CONFIG_MK}
+echo "CFLAGS = $CFLAGS" >> ${CONFIG_MK}
+echo "LDFLAGS = $LDFLAGS" >> ${CONFIG_MK}
+echo "LIBS = $LIBS" >> ${CONFIG_MK}
+echo >> ${CONFIG_MK}
+echo "CFLAGS_ASAN = $CFLAGS_ASAN" >> ${CONFIG_MK}
+echo "LDFLAGS_ASAN = $LDFLAGS_ASAN" >> ${CONFIG_MK}
+echo "LIBS_ASAN = $LIBS_ASAN" >> ${CONFIG_MK}
+echo >> ${CONFIG_MK}
+echo "CFLAGS_COV = $CFLAGS_COV" >> ${CONFIG_MK}
+echo "LDFLAGS_COV = $LDFLAGS_COV" >> ${CONFIG_MK}
+echo "LIBS_COV = $LIBS_COV" >> ${CONFIG_MK}
+echo >> ${CONFIG_MK}
+echo "CFLAGS_DEBUG = $CFLAGS_DEBUG" >> ${CONFIG_MK}
+echo "LDFLAGS_DEBUG = $LDFLAGS_DEBUG" >> ${CONFIG_MK}
+echo "LIBS_DEBUG = $LIBS_DEBUG" >> ${CONFIG_MK}
+
+for SRC in $SOURCES; do
+ echo >> ${CONFIG_MK}
+ SRC_LO="$(c2lo "$SRC")"
+ lo_rule "$SRC" >> ${CONFIG_MK}
+ echo " ${LIBTOOL} --tag=CC --mode=compile \${CC} \${CPPFLAGS} \${CFLAGS} -c $SRC -o $SRC_LO" >> ${CONFIG_MK}
+
+ echo >> ${CONFIG_MK}
+ SRC_ASAN_LO="$(c2ext .asan.lo "$SRC")"
+ ext_rule .asan.lo "$SRC" >> ${CONFIG_MK}
+ echo " ${LIBTOOL} --tag=CC --mode=compile \${CC} \${CPPFLAGS} \${CFLAGS_ASAN} -c $SRC -o $SRC_ASAN_LO" >> ${CONFIG_MK}
+
+ echo >> ${CONFIG_MK}
+ SRC_COV_LO="$(c2ext .cov.lo "$SRC")"
+ ext_rule .cov.lo "$SRC" >> ${CONFIG_MK}
+ echo " ${LIBTOOL} --tag=CC --mode=compile \${CC} \${CPPFLAGS} \${CFLAGS_COV} -c $SRC -o $SRC_COV_LO" >> ${CONFIG_MK}
+
+ echo >> ${CONFIG_MK}
+ SRC_DEBUG_LO="$(c2ext .debug.lo "$SRC")"
+ ext_rule .debug.lo "$SRC" >> ${CONFIG_MK}
+ echo " ${LIBTOOL} --tag=CC --mode=compile \${CC} \${CPPFLAGS} \${CFLAGS_DEBUG} -c $SRC -o $SRC_DEBUG_LO" >> ${CONFIG_MK}
+done
+
+echo >> ${CONFIG_MK}
+echo "$PROG: $LIBC3 $OBJECTS" >> ${CONFIG_MK}
+echo " ${LIBTOOL} --tag=CC --mode=link \${CC} \${CFLAGS} \${LDFLAGS} ${OBJECTS} ${LIBS} -o $PROG" >> ${CONFIG_MK}
+
+echo >> ${CONFIG_MK}
+echo "$PROG_ASAN: $LIBC3_ASAN $OBJECTS_ASAN" >> ${CONFIG_MK}
+echo " ${LIBTOOL} --tag=CC --mode=link \${CC} \${CFLAGS_ASAN} \${LDFLAGS_ASAN} ${OBJECTS_ASAN} ${LIBS_ASAN} -o $PROG_ASAN" >> ${CONFIG_MK}
+
+echo >> ${CONFIG_MK}
+echo "$PROG_COV: $LIBC3_COV $OBJECTS_COV" >> ${CONFIG_MK}
+echo " ${LIBTOOL} --tag=CC --mode=link \${CC} \${CFLAGS_COV} \${LDFLAGS_COV} ${OBJECTS_COV} ${LIBS_COV} -o $PROG_COV" >> ${CONFIG_MK}
+
+echo >> ${CONFIG_MK}
+echo "$PROG_DEBUG: $LIBC3_DEBUG $OBJECTS_DEBUG" >> ${CONFIG_MK}
+echo " ${LIBTOOL} --tag=CC --mode=link \${CC} \${CFLAGS_DEBUG} \${LDFLAGS_DEBUG} ${OBJECTS_DEBUG} ${LIBS_DEBUG} -o $PROG_DEBUG" >> ${CONFIG_MK}
+
+update_config_mk
diff --git a/configure b/configure
index 77e5a09..0bdba3f 100755
--- a/configure
+++ b/configure
@@ -20,6 +20,7 @@ export C3_TOP="$(pwd)"
( cd ucd2c && ./configure; )
( cd libc3 && ./configure; )
( cd ic3 && ./configure; )
+( cd c3s && ./configure; )
( cd test && ./configure; )
. ./config.subr
diff --git a/ic3/ic3.c b/ic3/ic3.c
index 2e36744..08f7b06 100644
--- a/ic3/ic3.c
+++ b/ic3/ic3.c
@@ -82,7 +82,7 @@ int main (int argc, char **argv)
env_init(&env);
while ((r = buf_xfer_spaces(&out, &in)) >= 0) {
if ((r = buf_parse_tag(&in, &input)) > 0) {
- if (! eval_tag(&env, &result, &input)) {
+ if (! eval_tag(&env, &input, &result)) {
tag_clean(&input);
continue;
}
@@ -101,8 +101,6 @@ int main (int argc, char **argv)
(r == 0 &&
(r = buf_ignore_character(&in)) <= 0))
break;
- if ((r = buf_refill_compact(&in)) < 0)
- break;
}
env_clean(&env);
buf_readline_close(&in);
diff --git a/libc3/binding.c b/libc3/binding.c
new file mode 100644
index 0000000..435d600
--- /dev/null
+++ b/libc3/binding.c
@@ -0,0 +1,62 @@
+/* c3
+ * Copyright 2022 kmx.io <contact@kmx.io>
+ *
+ * Permission is hereby granted to use this software granted
+ * the above copyright notice and this permission paragraph
+ * are included in all copies and substantial portions of this
+ * software.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS-IS" WITHOUT ANY GUARANTEE OF
+ * PURPOSE AND PERFORMANCE. IN NO EVENT WHATSOEVER SHALL THE
+ * AUTHOR BE CONSIDERED LIABLE FOR THE USE AND PERFORMANCE OF
+ * THIS SOFTWARE.
+ */
+#include <assert.h>
+#include <err.h>
+#include <stdlib.h>
+#include "binding.h"
+#include "list.h"
+
+void binding_delete (s_binding *binding)
+{
+ free(binding);
+}
+
+void binding_delete_all (s_binding *binding)
+{
+ s_binding *next;
+ while (binding) {
+ next = binding->next;
+ binding_delete(binding);
+ binding = next;
+ }
+}
+
+const s_tag * binding_get (s_binding *binding, const s_sym *name)
+{
+ while (binding) {
+ if (binding->name == name)
+ return binding->value;
+ binding = binding->next;
+ }
+ return NULL;
+}
+
+s_binding * binding_init (s_binding *binding, const s_sym *name,
+ const s_tag *value, s_binding *next)
+{
+ assert(binding);
+ binding->name = name;
+ binding->value = value;
+ binding->next = next;
+ return binding;
+}
+
+s_binding * binding_new (const s_sym *name, const s_tag *value,
+ s_binding *next)
+{
+ s_binding *binding;
+ if (! (binding = malloc(sizeof(s_binding))))
+ errx(1, "binding_new: out of memory");
+ return binding_init(binding, name, value, next);
+}
diff --git a/libc3/binding.h b/libc3/binding.h
new file mode 100644
index 0000000..054103b
--- /dev/null
+++ b/libc3/binding.h
@@ -0,0 +1,35 @@
+/* c3
+ * Copyright 2022 kmx.io <contact@kmx.io>
+ *
+ * Permission is hereby granted to use this software granted
+ * the above copyright notice and this permission paragraph
+ * are included in all copies and substantial portions of this
+ * software.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS-IS" WITHOUT ANY GUARANTEE OF
+ * PURPOSE AND PERFORMANCE. IN NO EVENT WHATSOEVER SHALL THE
+ * AUTHOR BE CONSIDERED LIABLE FOR THE USE AND PERFORMANCE OF
+ * THIS SOFTWARE.
+ */
+#ifndef BINDING_H
+#define BINDING_H
+
+#include "types.h"
+
+/* stack-allocation compatible functions */
+void binding_clean (s_binding *binding);
+s_binding * binding_init (s_binding *binding, const s_sym *name,
+ const s_tag *value, s_binding *next);
+
+/* constructors */
+s_binding * binding_new (const s_sym *name, const s_tag *value,
+ s_binding *next);
+
+/* destructors */
+void binding_delete (s_binding *binding);
+void binding_delete_all (s_binding *binding);
+
+/* observers */
+const s_tag * binding_get (s_binding *binding, const s_sym *name);
+
+#endif /* BINDING_H */
diff --git a/libc3/buf_inspect.c b/libc3/buf_inspect.c
index e5a7ec5..0769c0f 100644
--- a/libc3/buf_inspect.c
+++ b/libc3/buf_inspect.c
@@ -46,7 +46,7 @@ sw buf_inspect_call (s_buf *buf, const s_call *call)
if ((r = buf_inspect_ident(buf, &call->ident)) < 0)
return r;
result += r;
- if ((r = buf_inspect_call_args(buf, call->args)) < 0)
+ if ((r = buf_inspect_call_args(buf, call->arguments)) < 0)
return r;
result += r;
return result;
@@ -87,7 +87,7 @@ sw buf_inspect_call_size (const s_call *call)
if ((r = buf_inspect_ident_size(&call->ident)) < 0)
return r;
result += r;
- if ((r = buf_inspect_call_args_size(call->args)) < 0)
+ if ((r = buf_inspect_call_args_size(call->arguments)) < 0)
return r;
result += r;
return result;
@@ -786,11 +786,14 @@ sw buf_inspect_tag (s_buf *buf, const s_tag *tag)
switch(tag->type.type) {
case TAG_VOID: return 0;
case TAG_BOOL: return buf_inspect_bool(buf, tag->data.bool);
+ case TAG_CALL:
+ case TAG_CALL_FUNCTION:
+ case TAG_CALL_MACRO:
+ return buf_inspect_call(buf, &tag->data.call);
case TAG_CHARACTER:
return buf_inspect_character(buf, tag->data.character);
case TAG_F32: return buf_inspect_f32(buf, tag->data.f32);
case TAG_F64: return buf_inspect_f64(buf, tag->data.f64);
- case TAG_CALL: return buf_inspect_call(buf, &tag->data.call);
case TAG_IDENT: return buf_inspect_ident(buf, &tag->data.ident);
case TAG_INTEGER: return buf_inspect_integer(buf, &tag->data.integer);
case TAG_LIST: return buf_inspect_list(buf, tag->data.list);
@@ -819,11 +822,14 @@ sw buf_inspect_tag_size (const s_tag *tag)
switch(tag->type.type) {
case TAG_VOID: return 0;
case TAG_BOOL: return buf_inspect_bool_size(tag->data.bool);
+ case TAG_CALL:
+ case TAG_CALL_FUNCTION:
+ case TAG_CALL_MACRO:
+ return buf_inspect_call_size(&tag->data.call);
case TAG_CHARACTER:
return buf_inspect_character_size(tag->data.character);
case TAG_F32: return buf_inspect_f32_size(tag->data.f32);
case TAG_F64: return buf_inspect_f64_size(tag->data.f64);
- case TAG_CALL: return buf_inspect_call_size(&tag->data.call);
case TAG_IDENT: return buf_inspect_ident_size(&tag->data.ident);
case TAG_INTEGER: return buf_inspect_integer_size(&tag->data.integer);
case TAG_LIST: return buf_inspect_list_size(tag->data.list);
diff --git a/libc3/buf_parse.c b/libc3/buf_parse.c
index 8440694..5ccc13c 100644
--- a/libc3/buf_parse.c
+++ b/libc3/buf_parse.c
@@ -74,7 +74,7 @@ sw buf_parse_call (s_buf *buf, s_call *call)
if ((r = buf_parse_ident(buf, &call->ident)) <= 0)
goto clean;
result += r;
- if ((r = buf_parse_call_args(buf, &call->args)) <= 0)
+ if ((r = buf_parse_call_args(buf, &call->arguments)) <= 0)
goto restore;
result += r;
r = result;
diff --git a/libc3/call.c b/libc3/call.c
index 8e6d3e8..9f4e02e 100644
--- a/libc3/call.c
+++ b/libc3/call.c
@@ -22,7 +22,7 @@
void call_clean (s_call *call)
{
assert(call);
- list_delete(call->args);
+ list_delete(call->arguments);
}
s8 call_compare (const s_call *a, const s_call *b)
@@ -36,7 +36,7 @@ s8 call_compare (const s_call *a, const s_call *b)
return 1;
if ((r = ident_compare(&a->ident, &b->ident)))
return r;
- return list_compare(a->args, b->args);
+ return list_compare(a->arguments, b->arguments);
}
s_call * call_copy (const s_call *src, s_call *dest)
@@ -44,7 +44,7 @@ s_call * call_copy (const s_call *src, s_call *dest)
assert(src);
assert(dest);
ident_copy(&src->ident, &dest->ident);
- list_copy(src->args, &dest->args);
+ list_copy(src->arguments, &dest->arguments);
return dest;
}
@@ -53,7 +53,7 @@ t_hash_context * call_hash_update (t_hash_context *context,
{
assert(x);
ident_hash_update(context, &x->ident);
- return list_hash_update(context, x->args);
+ return list_hash_update(context, x->arguments);
}
s_call * call_init_1 (s_call *call, const s8 *p)
diff --git a/libc3/eval.c b/libc3/eval.c
index 509e20b..9e3cd0b 100644
--- a/libc3/eval.c
+++ b/libc3/eval.c
@@ -12,17 +12,130 @@
* THIS SOFTWARE.
*/
#include <assert.h>
+#include <err.h>
+#include <stdlib.h>
+#include "binding.h"
#include "env.h"
#include "eval.h"
+#include "frame.h"
+#include "list.h"
#include "tag.h"
-s_tag * eval_tag (s_env *env, s_tag *dest, s_tag *tag)
+s_tag * eval_call_function (s_env *env, s_call *call, s_tag *dest)
{
+ s_arg *args;
+ s_list *call_args;
+ s_frame frame;
+ s_function *function;
+ s_tag tmp;
+ assert(env);
+ assert(call);
+ assert(dest);
+ function = call->function;
+ assert(function);
+ frame_init(&frame, env->frame);
+ frame.bindings = function->bindings;
+ args = function->args;
+ call_args = call->arguments;
+ while (args) {
+ if (! call_args) {
+ assert(! "eval_function_call: missing argument");
+ errx(1, "eval_function_call: missing argument");
+ return NULL;
+ }
+ eval_tag(env, &call_args->tag, &tmp);
+ frame.bindings = binding_new(args->name, &call_args->tag,
+ frame.bindings);
+ args = args->next;
+ call_args = list_next(call_args);
+ }
+ if (call_args) {
+ assert(! "eval_function_call: too many arguments");
+ errx(1, "eval_function_call: too many arguments");
+ return NULL;
+ }
+ env->frame = &frame;
+ eval_progn(env, function->program, dest);
+ env->frame = frame_clean(&frame);
+ return dest;
+}
+
+s_tag * eval_call_macro (s_env *env, s_call *call, s_tag *dest)
+{
+ s_tag *expanded;
+ assert(env);
+ assert(call);
+ assert(dest);
(void) env;
+ (void) call;
+ (void) expanded;
+ return dest;
+}
+
+const s_tag * eval_ident (s_env *env, s_ident *ident)
+{
+ const s_tag *tag;
+ assert(env);
+ assert(ident);
+ assert(dest);
+ if (! (tag = frame_get(env->frame, ident->sym))) {
+ assert(! "eval_ident: unbound variable");
+ errx(1, "eval_ident: unbound variable");
+ }
+ return tag;
+}
+
+s_tag * eval_progn (s_env *env, s_list *program, s_tag *dest)
+{
+ s_tag tmp;
+ assert(env);
+ assert(program);
+ assert(dest);
+ while (program) {
+ eval_tag(env, &program->tag, &tmp);
+ program = list_next(program);
+ }
+ *dest = tmp;
+ return dest;
+}
+
+s_tag * eval_tag (s_env *env, s_tag *tag, s_tag *dest)
+{
switch (tag->type.type) {
- default:
+ case TAG_VOID: return tag_init_void(dest);
+ case TAG_CALL:
+ assert(! "eval_tag: invalid tag type: TAG_CALL");
+ errx(1, "eval_tag: invalid tag type TAG_CALL");
+ return NULL;
+ case TAG_CALL_FUNCTION:
+ return eval_call_function(env, &tag->data.call, dest);
+ case TAG_CALL_MACRO:
+ return eval_call_macro(env, &tag->data.call, dest);
+ case TAG_IDENT:
+ return tag_copy(eval_ident(env, &tag->data.ident), dest);
+ case TAG_BOOL:
+ case TAG_CHARACTER:
+ case TAG_F32:
+ case TAG_F64:
+ case TAG_INTEGER:
+ case TAG_LIST:
+ case TAG_PTAG:
+ case TAG_QUOTE:
+ case TAG_S16:
+ case TAG_S32:
+ case TAG_S64:
+ case TAG_S8:
+ case TAG_STR:
+ case TAG_SYM:
+ case TAG_TUPLE:
+ case TAG_U16:
+ case TAG_U32:
+ case TAG_U64:
+ case TAG_U8:
+ case TAG_VAR:
return tag_copy(tag, dest);
}
- assert(! "error");
+ assert(! "eval_tag: invalid tag");
+ errx(1, "eval_tag: invalid tag");
return NULL;
}
diff --git a/libc3/eval.h b/libc3/eval.h
index 0c37a24..77f0a8b 100644
--- a/libc3/eval.h
+++ b/libc3/eval.h
@@ -16,6 +16,13 @@
#include "types.h"
-s_tag * eval_tag (s_env *env, s_tag *dest, s_tag *tag);
+s_tag * eval_call_function (s_env *env, s_call *call,
+ s_tag *dest);
+s_tag * eval_call_macro (s_env *env, s_call *call, s_tag *dest);
+s_tag * eval_function (s_env *env, s_function *function,
+ s_tag *dest);
+const s_tag * eval_ident (s_env *env, s_ident *ident);
+s_tag * eval_progn (s_env *env, s_list *program, s_tag *dest);
+s_tag * eval_tag (s_env *env, s_tag *tag, s_tag *dest);
#endif /* EVAL_H */
diff --git a/libc3/frame.c b/libc3/frame.c
index 9205298..54c5f06 100644
--- a/libc3/frame.c
+++ b/libc3/frame.c
@@ -14,13 +14,17 @@
#include <assert.h>
#include <err.h>
#include <stdlib.h>
+#include "binding.h"
#include "frame.h"
#include "list.h"
-void frame_clean (s_frame *frame)
+s_frame * frame_clean (s_frame *frame)
{
+ s_frame *next;
assert(frame);
- list_delete(frame->bindings);
+ next = frame->next;
+ binding_delete_all(frame->bindings);
+ return next;
}
void frame_delete (s_frame *frame)
@@ -41,6 +45,17 @@ void frame_delete_all (s_frame *frame)
}
}
+const s_tag * frame_get (s_frame *frame, const s_sym *sym)
+{
+ const s_tag *tag;
+ while (frame) {
+ if ((tag = binding_get(frame->bindings, sym)))
+ return tag;
+ frame = frame->next;
+ }
+ return NULL;
+}
+
s_frame * frame_init (s_frame *frame, s_frame *next)
{
assert(frame);
diff --git a/libc3/frame.h b/libc3/frame.h
index 882fa0d..fcb8efd 100644
--- a/libc3/frame.h
+++ b/libc3/frame.h
@@ -17,7 +17,7 @@
#include "types.h"
/* stack-allocation compatible functions */
-void frame_clean (s_frame *frame);
+s_frame * frame_clean (s_frame *frame);
s_frame * frame_init (s_frame *frame, s_frame *next);
/* constructors */
@@ -27,4 +27,7 @@ s_frame * frame_new ();
void frame_delete (s_frame *frame);
void frame_delete_all (s_frame *frame);
+/* observers */
+const s_tag * frame_get (s_frame *frame, const s_sym *sym);
+
#endif /* FRAME_H */
diff --git a/libc3/function.h b/libc3/function.h
new file mode 100644
index 0000000..bbb7a13
--- /dev/null
+++ b/libc3/function.h
@@ -0,0 +1,22 @@
+/* c3
+ * Copyright 2022 kmx.io <contact@kmx.io>
+ *
+ * Permission is hereby granted to use this software granted
+ * the above copyright notice and this permission paragraph
+ * are included in all copies and substantial portions of this
+ * software.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS-IS" WITHOUT ANY GUARANTEE OF
+ * PURPOSE AND PERFORMANCE. IN NO EVENT WHATSOEVER SHALL THE
+ * AUTHOR BE CONSIDERED LIABLE FOR THE USE AND PERFORMANCE OF
+ * THIS SOFTWARE.
+ */
+#ifndef FUNCTION_H
+#define FUNCTION_H
+
+#include "types.h"
+
+s_function * function_init (s_function *function);
+void function_clean (s_function *function);
+
+#endif /* FUNCTION_H */
diff --git a/libc3/tag.c b/libc3/tag.c
index f355317..0dd83ce 100644
--- a/libc3/tag.c
+++ b/libc3/tag.c
@@ -150,7 +150,10 @@ s8 tag_compare (const s_tag *a, const s_tag *b) {
switch (a->type.type) {
case TAG_VOID: return 0;
case TAG_BOOL: return bool_compare(a->data.bool, b->data.bool);
- case TAG_CALL: return call_compare(&a->data.call, &b->data.call);
+ case TAG_CALL:
+ case TAG_CALL_FUNCTION:
+ case TAG_CALL_MACRO:
+ return call_compare(&a->data.call, &b->data.call);
case TAG_CHARACTER: return character_compare(a->data.character,
b->data.character);
case TAG_F32: return f32_compare(a->data.f32, b->data.f32);
@@ -238,7 +241,10 @@ t_hash_context * tag_hash_update (t_hash_context *context,
switch (tag->type.type) {
case TAG_VOID: break;
case TAG_BOOL: bool_hash_update(context, tag->data.bool); break;
- case TAG_CALL: call_hash_update(context, &tag->data.call); break;
+ case TAG_CALL:
+ case TAG_CALL_FUNCTION:
+ case TAG_CALL_MACRO:
+ call_hash_update(context, &tag->data.call); break;
case TAG_CHARACTER:
character_hash_update(context, tag->data.character); break;
case TAG_F32: f32_hash_update(context, tag->data.f32); break;
diff --git a/libc3/tag.h b/libc3/tag.h
index 026e7b0..d6bbaed 100644
--- a/libc3/tag.h
+++ b/libc3/tag.h
@@ -53,7 +53,8 @@ s_tag * tag_init_s32 (s_tag *tag, s32 i);
s_tag * tag_init_s64 (s_tag *tag, s64 i);
s_tag * tag_init_sym (s_tag *tag, const s_sym *p);
s_tag * tag_init_sym_1 (s_tag *tag, const s8 *p);
-s_tag * tag_init_tuple (s_tag *tag, const s_tuple *tuple);
+s_tag * tag_init_tuple (s_tag *tag, uw count);
+s_tag * tag_init_tuple_2 (s_tag *tag, s_tag *a, s_tag *b);
s_tag * tag_init_u8 (s_tag *tag, u8 i);
s_tag * tag_init_u16 (s_tag *tag, u16 i);
s_tag * tag_init_u32 (s_tag *tag, u32 i);
@@ -76,6 +77,7 @@ s_tag * tag_new_s8 (s8 i);
s_tag * tag_new_s16 (s16 i);
s_tag * tag_new_s32 (s32 i);
s_tag * tag_new_s64 (s64 i);
+s_tag * tag_new_tuple_2 (s_tag *a, s_tag *b);
s_tag * tag_new_u8 (u8 i);
s_tag * tag_new_u16 (u16 i);
s_tag * tag_new_u32 (u32 i);
diff --git a/libc3/types.h b/libc3/types.h
index 54ac241..02e7e7c 100644
--- a/libc3/types.h
+++ b/libc3/types.h
@@ -37,65 +37,163 @@ typedef double f64;
/* Boolean : true or false. */
typedef s8 bool;
+/* enums */
typedef enum {
false = 0,
true = 1
} e_bool;
-/* character */
-typedef s32 character;
+typedef enum {
+ TAG_VOID = 0,
+ TAG_BOOL = 1,
+ TAG_CALL,
+ TAG_CALL_FUNCTION,
+ TAG_CALL_MACRO,
+ TAG_CHARACTER,
+ TAG_F32,
+ TAG_F64,
+ TAG_IDENT,
+ TAG_INTEGER,
+ TAG_S64,
+ TAG_S32,
+ TAG_S16,
+ TAG_S8,
+ TAG_U8,
+ TAG_U16,
+ TAG_U32,
+ TAG_U64,
+ TAG_LIST,
+ TAG_PTAG,
+ TAG_QUOTE,
+ TAG_STR,
+ TAG_SYM,
+ TAG_TUPLE,
+ TAG_VAR
+} e_tag_type;
-/* integer */
-typedef struct integer {
- mp_int mp_int;
-} s_integer;
+/* structs */
+typedef struct arg s_arg;
+typedef struct binding s_binding;
+typedef struct buf s_buf;
+typedef struct buf_save s_buf_save;
+typedef struct call s_call;
+typedef struct env s_env;
+typedef struct error_handler s_error_handler;
+typedef struct fact s_fact;
+typedef struct facts s_facts;
+typedef struct facts_cursor s_facts_cursor;
+typedef struct facts_spec_cursor s_facts_spec_cursor;
+typedef struct facts_with_cursor s_facts_with_cursor;
+typedef struct facts_with_cursor_level s_facts_with_cursor_level;
+typedef struct frame s_frame;
+typedef struct function s_function;
+typedef struct ident s_ident;
+typedef struct integer s_integer;
+typedef struct list s_list;
+typedef struct module s_module;
+typedef struct str s_str;
+typedef struct sym s_sym;
+typedef struct sym_list s_sym_list;
+typedef struct tag s_tag;
+typedef struct tuple s_tuple;
+
+/* unions */
+typedef union ptr u_ptr;
+typedef union ptr_w u_ptr_w;
+typedef union tag_data u_tag_data;
+typedef union tag_type u_tag_type;
+
+/* typedefs */
+typedef s32 character;
+typedef s_tag **p_facts_spec;
+typedef s_tag *p_quote;
+typedef const s_tag *p_tag;
+typedef const s_tag *p_var;
+
+/* 1 */
+struct buf_save {
+ s_buf_save *next;
+ uw rpos;
+ uw wpos;
+};
+
+struct env {
+ s_frame *frame;
+ s_error_handler *error_handler;
+};
+
+struct error_handler
+{
+ jmp_buf jmp_buf;
+ s_error_handler *next;
+};
-/* ptr */
-typedef union ptr {
+struct fact {
+ const s_tag *subject;
+ const s_tag *predicate;
+ const s_tag *object;
+ uw id;
+};
+
+struct frame {
+ s_binding *bindings;
+ s_frame *next;
+};
+
+struct function {
+ uw arity;
+ s_arg *args;
+ s_binding *bindings;
+ s_list *program;
+};
+
+struct ident {
+ const s_sym *module;
+ const s_sym *sym;
+};
+
+struct module {
+ const s_sym *name;
+ s_facts *facts;
+};
+
+union ptr {
const void *p;
const s8 *ps8;
const u8 *pu8;
-} u_ptr;
+};
-typedef union ptr_w {
+union ptr_w {
void *p;
s8 *ps8;
u8 *pu8;
-} u_ptr_w;
-
-/* str */
-typedef struct str {
- u_ptr_w free; /**< Pointer to free or NULL. */
- uw size; /**< Size in bytes. */
- u_ptr ptr; /**< Pointer to memory. */
-} s_str;
-
-/* sym */
-typedef struct sym_list s_sym_list;
-
-typedef struct sym {
- s_str str;
-} s_sym;
+};
struct sym_list {
s_sym *sym;
s_sym_list *next;
};
-/* ident */
-typedef struct ident {
- const s_sym *module;
- const s_sym *sym;
-} s_ident;
+union tag_type {
+ e_tag_type type;
+};
-/* buf */
-typedef struct buf s_buf;
-typedef struct buf_save s_buf_save;
+struct tuple {
+ uw count;
+ s_tag *tag;
+};
-struct buf_save {
- s_buf_save *next;
- uw rpos;
- uw wpos;
+/* 2 */
+struct arg {
+ const s_sym *name;
+ s_ident type;
+ s_arg *next;
+};
+
+struct binding {
+ const s_sym *name;
+ const s_tag *value;
+ s_binding *next;
};
struct buf {
@@ -112,61 +210,38 @@ struct buf {
u64 wpos;
};
-/* tag */
-typedef struct tag s_tag;
-typedef struct list s_list;
-
-typedef s_tag * p_quote;
-typedef const s_tag * p_tag;
-
-typedef struct tuple {
- uw count;
- s_tag *tag;
-} s_tuple;
-
-typedef struct call {
+struct call {
s_ident ident;
- s_list *args;
-} s_call;
+ s_list *arguments;
+ s_function *function;
+};
-typedef const s_tag * p_var;
+struct facts_spec_cursor {
+ p_facts_spec spec;
+ const s_tag *subject;
+ uw pos;
+};
-typedef enum tag_type {
- TAG_VOID = 0,
- TAG_BOOL = 1,
- TAG_CHARACTER,
- TAG_F32,
- TAG_F64,
- TAG_CALL,
- TAG_IDENT,
- TAG_INTEGER,
- TAG_S64,
- TAG_S32,
- TAG_S16,
- TAG_S8,
- TAG_U8,
- TAG_U16,
- TAG_U32,
- TAG_U64,
- TAG_LIST,
- TAG_PTAG,
- TAG_QUOTE,
- TAG_STR,
- TAG_SYM,
- TAG_TUPLE,
- TAG_VAR
-} e_tag_type;
+struct integer {
+ mp_int mp_int;
+};
-typedef union tag_type_ {
- e_tag_type type;
-} u_tag_type;
+struct str {
+ u_ptr_w free; /**< Pointer to free or NULL. */
+ uw size; /**< Size in bytes. */
+ u_ptr ptr; /**< Pointer to memory. */
+};
+
+struct sym {
+ s_str str;
+};
-typedef union tag_data {
+union tag_data {
bool bool;
+ s_call call;
character character;
f32 f32;
f64 f64;
- s_call call;
s_ident ident;
s_integer integer;
s_list *list;
@@ -184,28 +259,20 @@ typedef union tag_data {
u32 u32;
u64 u64;
p_var var;
-} u_tag_data;
+};
+/* 3 */
struct tag {
u_tag_type type;
u_tag_data data;
};
-/* list */
+/* 4 */
struct list {
s_tag tag;
s_tag next;
};
-/* fact */
-typedef struct fact {
- const s_tag *subject;
- const s_tag *predicate;
- const s_tag *object;
- uw id;
-} s_fact;
-
-/* set */
#define TYPEDEF_SET_ITEM(name, type) \
typedef struct set_item__##name s_set_item__##name; \
\
@@ -241,7 +308,6 @@ TYPEDEF_SET(fact, s_fact);
TYPEDEF_SET_CURSOR(tag);
TYPEDEF_SET_CURSOR(fact);
-/* skiplist */
#define TYPEDEF_SKIPLIST_NODE(name, type) \
typedef struct skiplist_node__##name { \
type name; \
@@ -260,17 +326,17 @@ TYPEDEF_SKIPLIST_NODE(fact, s_fact *);
TYPEDEF_SKIPLIST(fact, s_fact *);
-/* facts */
-typedef struct facts {
+/* 5 */
+struct facts {
s_set__tag tags;
s_set__fact facts;
s_skiplist__fact *index_spo;
s_skiplist__fact *index_pos;
s_skiplist__fact *index_osp;
s_buf *log;
-} s_facts;
+};
-typedef struct facts_cursor {
+struct facts_cursor {
s_skiplist__fact *index;
s_skiplist_node__fact *node;
s_fact start;
@@ -278,59 +344,23 @@ typedef struct facts_cursor {
s_tag *var_subject;
s_tag *var_predicate;
s_tag *var_object;
-} s_facts_cursor;
-
-typedef s_tag ** p_facts_spec;
-
-typedef struct facts_spec_cursor {
- p_facts_spec spec;
- const s_tag *subject;
- uw pos;
-} s_facts_spec_cursor;
+};
-typedef struct facts_with_cursor_level {
+/* 6 */
+struct facts_with_cursor_level {
s_facts_cursor cursor;
s_fact *fact;
p_facts_spec spec;
-} s_facts_with_cursor_level;
+};
-typedef struct facts_with_cursor {
+/* 7 */
+struct facts_with_cursor {
const s_facts *facts;
- s_list *bindings;
+ s_binding *bindings;
size_t facts_count;
s_facts_with_cursor_level *levels;
size_t level;
p_facts_spec spec;
-} s_facts_with_cursor;
-
-/* module */
-typedef struct module {
- const s_sym *name;
- s_facts *facts;
-} s_module;
-
-/* error_handler */
-typedef struct error_handler s_error_handler;
-typedef const s_sym * (* f_error_handler) (s_error_handler *);
-
-struct error_handler
-{
- jmp_buf jmp_buf;
- s_error_handler *next;
-};
-
-/* frame */
-typedef struct frame s_frame;
-
-struct frame {
- s_list *bindings;
- s_frame *next;
};
-/* env */
-typedef struct env {
- s_frame *frame;
- s_error_handler *error_handler;
-} s_env;
-
#endif /* TYPES_H */
diff --git a/test/ic3_test b/test/ic3_test
index 46cb819..83ad141 100755
--- a/test/ic3_test
+++ b/test/ic3_test
@@ -35,14 +35,27 @@ else
fi
for TARGET in $TARGETS; do
+ RESULT=test_ok
$IC3 < ${TARGET}.in > ${TARGET}.out 2> ${TARGET}.err
echo $? > ${TARGET}.ret
- diff -u ${TARGET}.out.expected ${TARGET}.out > ${TARGET}.diff &&
- diff -u ${TARGET}.err.expected ${TARGET}.err >> ${TARGET}.diff &&
- diff -u ${TARGET}.ret.expected ${TARGET}.ret >> ${TARGET}.diff &&
- rm ${TARGET}.diff &&
- test_ok ||
+ if ! diff -u ${TARGET}.out.expected ${TARGET}.out > ${TARGET}.diff
+ then
+ RESULT=test_ko
+ fi
+ if ! diff -u ${TARGET}.err.expected ${TARGET}.err >> ${TARGET}.diff
+ then
+ RESULT=test_ko
+ fi
+ if ! diff -u ${TARGET}.ret.expected ${TARGET}.ret >> ${TARGET}.diff
+ then
+ RESULT=test_ko
+ fi
+ if [ "x$RESULT" = "xtest_ok" ]; then
+ rm ${TARGET}.diff
+ test_ok
+ else
test_ko
+ fi
done
echo
for TARGET in $TARGETS; do