summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohannes Weiner <hannes@cmpxchg.org>2010-05-11 02:32:45 +0200
committerJohannes Weiner <hannes@cmpxchg.org>2010-05-11 02:32:45 +0200
commitecb0fc4a44f798e608e3ac97df3a3527c3eb36b3 (patch)
tree586fa855881037337c1d7aadef2b1b6dd6f7428d
parent81323fd2afcfc2e878625076c50a96eef6698876 (diff)
sequence: support unlimited arguments to (concat)
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
-rw-r--r--include/sheep/object_types.h2
-rw-r--r--include/sheep/unpack.h1
-rw-r--r--include/sheep/util.h1
-rw-r--r--sheep/list.c32
-rw-r--r--sheep/sequence.c16
-rw-r--r--sheep/string.c35
-rw-r--r--sheep/unpack.c24
-rw-r--r--sheep/util.c15
8 files changed, 88 insertions, 38 deletions
diff --git a/include/sheep/object_types.h b/include/sheep/object_types.h
index 027ccde..c2d4a9e 100644
--- a/include/sheep/object_types.h
+++ b/include/sheep/object_types.h
@@ -18,7 +18,7 @@ struct sheep_vm;
struct sheep_sequence {
size_t (*length)(sheep_t);
- sheep_t (*concat)(struct sheep_vm *, sheep_t, sheep_t);
+ sheep_t (*concat)(struct sheep_vm *, sheep_t, unsigned int);
sheep_t (*reverse)(struct sheep_vm *, sheep_t);
sheep_t (*nth)(struct sheep_vm *, size_t, sheep_t);
sheep_t (*position)(struct sheep_vm *, sheep_t, sheep_t);
diff --git a/include/sheep/unpack.h b/include/sheep/unpack.h
index a0ebf2a..052830e 100644
--- a/include/sheep/unpack.h
+++ b/include/sheep/unpack.h
@@ -11,6 +11,7 @@
#include <sheep/list.h>
#include <stdarg.h>
+int sheep_unpack(const char *, sheep_t, const char, ...);
int sheep_unpack_list(const char *, struct sheep_list *, const char *, ...);
int sheep_unpack_stack(const char *, struct sheep_vm *, unsigned int,
const char *, ...);
diff --git a/include/sheep/util.h b/include/sheep/util.h
index 80bd187..564c5eb 100644
--- a/include/sheep/util.h
+++ b/include/sheep/util.h
@@ -25,6 +25,7 @@ struct sheep_strbuf {
char *bytes;
size_t nr_bytes;
};
+void sheep_strbuf_addn(struct sheep_strbuf *, const char *, size_t);
void sheep_strbuf_add(struct sheep_strbuf *, const char *);
void sheep_strbuf_addf(struct sheep_strbuf *, const char *, ...);
diff --git a/sheep/list.c b/sheep/list.c
index 86fccb9..ba06752 100644
--- a/sheep/list.c
+++ b/sheep/list.c
@@ -102,22 +102,32 @@ static sheep_t do_list_concat(struct sheep_vm *vm, sheep_t base, sheep_t tail)
return base;
}
-static sheep_t list_concat(struct sheep_vm *vm, sheep_t a, sheep_t b)
+static sheep_t list_concat(struct sheep_vm *vm, sheep_t sheep,
+ unsigned int nr_args)
{
- sheep_t result, pos;
+ sheep_t start, pos, result = NULL;
+ unsigned int i;
- sheep_protect(vm, a);
- sheep_protect(vm, b);
+ sheep_protect(vm, sheep);
+
+ start = sheep_make_cons(vm, NULL, NULL);
+ sheep_protect(vm, start);
- result = pos = sheep_make_cons(vm, NULL, NULL);
- sheep_protect(vm, result);
+ pos = do_list_concat(vm, start, sheep);
+ for (i = 1; i < nr_args; i++) {
+ sheep_t list;
- pos = do_list_concat(vm, result, a);
- do_list_concat(vm, pos, b);
+ list = vm->stack.items[vm->stack.nr_items - nr_args + i];
+ if (sheep_unpack("concat", list, 'l', &list))
+ goto out;
- sheep_unprotect(vm, result);
- sheep_unprotect(vm, b);
- sheep_unprotect(vm, a);
+ pos = do_list_concat(vm, pos, list);
+ }
+ vm->stack.nr_items -= nr_args;
+ result = start;
+out:
+ sheep_unprotect(vm, start);
+ sheep_unprotect(vm, sheep);
return result;
}
diff --git a/sheep/sequence.c b/sheep/sequence.c
index c394637..631eb56 100644
--- a/sheep/sequence.c
+++ b/sheep/sequence.c
@@ -24,21 +24,21 @@ static sheep_t builtin_length(struct sheep_vm *vm, unsigned int nr_args)
return sheep_make_number(vm, len);
}
-/* (concat a b) */
+/* (concat first &rest rest) */
static sheep_t builtin_concat(struct sheep_vm *vm, unsigned int nr_args)
{
- sheep_t a, b;
+ sheep_t object;
- if (sheep_unpack_stack("concat", vm, nr_args, "qq", &a, &b))
+ if (!nr_args) {
+ fprintf(stderr, "concat: too few arguments\n");
return NULL;
+ }
- if (sheep_type(a) != sheep_type(b)) {
- fprintf(stderr, "concat: can not concat %s and %s\n",
- sheep_type(a)->name, sheep_type(b)->name);
+ object = vm->stack.items[vm->stack.nr_items - nr_args];
+ if (sheep_unpack("concat", object, 'q', &object))
return NULL;
- }
- return sheep_sequence(a)->concat(vm, a, b);
+ return sheep_sequence(object)->concat(vm, object, nr_args);
}
/* (reverse sequence) */
diff --git a/sheep/string.c b/sheep/string.c
index 3063d41..eae9580 100644
--- a/sheep/string.c
+++ b/sheep/string.c
@@ -58,20 +58,31 @@ static size_t string_length(sheep_t sheep)
return string->nr_bytes;
}
-static sheep_t string_concat(struct sheep_vm *vm, sheep_t a, sheep_t b)
+static sheep_t string_concat(struct sheep_vm *vm, sheep_t sheep,
+ unsigned int nr_args)
{
- struct sheep_string *sa, *sb;
- char *result;
- size_t len;
+ struct sheep_string *string;
+ struct sheep_strbuf sb;
+ unsigned int i;
- sa = sheep_string(a);
- sb = sheep_string(b);
- len = sa->nr_bytes + sb->nr_bytes;
- result = sheep_malloc(len + 1);
- memcpy(result, sa->bytes, sa->nr_bytes);
- memcpy(result + sa->nr_bytes, sb->bytes, sb->nr_bytes);
- result[len] = 0;
- return __sheep_make_string(vm, result, len);
+ memset(&sb, 0, sizeof(struct sheep_strbuf));
+
+ string = sheep_string(sheep);
+ sheep_strbuf_addn(&sb, string->bytes, string->nr_bytes);
+ for (i = 1; i < nr_args; i++) {
+ sheep_t string_;
+
+ string_ = vm->stack.items[vm->stack.nr_items - nr_args + i];
+ if (sheep_unpack("concat", string_, 'S', &string)) {
+ sheep_free(sb.bytes);
+ return NULL;
+ }
+
+ sheep_strbuf_addn(&sb, string->bytes, string->nr_bytes);
+ }
+
+ vm->stack.nr_items -= nr_args;
+ return __sheep_make_string(vm, sb.bytes, sb.nr_bytes);
}
static sheep_t string_reverse(struct sheep_vm *vm, sheep_t sheep)
diff --git a/sheep/unpack.c b/sheep/unpack.c
index bc1f2b9..ad7cdbc 100644
--- a/sheep/unpack.c
+++ b/sheep/unpack.c
@@ -94,6 +94,30 @@ static const char *unpack(int control, sheep_t object,
return NULL;
}
+int sheep_unpack(const char *caller, sheep_t object, const char item, ...)
+{
+ void **itemp, *next = NULL;
+ const char *wanted;
+ va_list ap;
+
+ va_start(ap, item);
+ itemp = va_arg(ap, void **);
+
+ wanted = unpack(item, object, itemp, &next);
+ if (wanted) {
+ fprintf(stderr, "%s: expected %s, got %s\n",
+ caller, wanted, sheep_type(object)->name);
+ va_end(ap);
+ return -1;
+ }
+
+ if (next)
+ *va_arg(ap, void **) = next;
+
+ va_end(ap);
+ return 0;
+}
+
int sheep_unpack_list(const char *caller, struct sheep_list *list,
const char *items, ...)
{
diff --git a/sheep/util.c b/sheep/util.c
index a92ec2c..42ae7cd 100644
--- a/sheep/util.c
+++ b/sheep/util.c
@@ -44,14 +44,17 @@ void sheep_free(const void *mem)
free((void *)mem);
}
-void sheep_strbuf_add(struct sheep_strbuf *sb, const char *str)
+void sheep_strbuf_addn(struct sheep_strbuf *sb, const char *str, size_t n)
{
- size_t len;
+ sb->bytes = sheep_realloc(sb->bytes, sb->nr_bytes + n + 1);
+ memcpy(sb->bytes + sb->nr_bytes, str, n);
+ sb->nr_bytes += n;
+ sb->bytes[sb->nr_bytes] = 0;
+}
- len = strlen(str);
- sb->bytes = sheep_realloc(sb->bytes, sb->nr_bytes + len + 1);
- memcpy(sb->bytes + sb->nr_bytes, str, len + 1);
- sb->nr_bytes += len;
+void sheep_strbuf_add(struct sheep_strbuf *sb, const char *str)
+{
+ sheep_strbuf_addn(sb, str, strlen(str));
}
#define DEFAULT_BUF 64