MBED port of https://github.com/ys1382/filagree . The only change is adding #define MBED

Dependents:   filagree_test

Revision:
0:1a89e28dea91
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sys.c	Wed May 30 21:13:01 2012 +0000
@@ -0,0 +1,430 @@
+#include "serial.h"
+#include "sys.h"
+#include "struct.h"
+#include "variable.h"
+#include "vm.h"
+#include "util.h"
+#include <stdio.h>
+#include <string.h>
+
+// system functions
+
+void sys_callback2c(struct Context *context)
+{
+    stack_pop(context->rhs); // self
+	context->callback2c(context);
+}
+
+void sys_print(struct Context *context)
+{
+    stack_pop(context->rhs); // self
+    struct variable *v;
+    while ((v = (struct variable*)stack_pop(context->rhs)))
+        printf("%s\n", variable_value_str(context, v));
+}
+
+void sys_save(struct Context *context)
+{
+    stack_pop(context->rhs); // self
+    struct variable *v = (struct variable*)stack_pop(context->rhs);
+    struct variable *path = (struct variable*)stack_pop(context->rhs);
+    variable_save(context, v, path);
+}
+
+void sys_load(struct Context *context)
+{
+    stack_pop(context->rhs); // self
+    struct variable *path = (struct variable*)stack_pop(context->rhs);
+    struct variable *v = variable_load(context, path);
+
+    if (v)
+        stack_push(context->operand_stack, v);
+}
+
+void sys_rm(struct Context *context)
+{
+    stack_pop(context->rhs); // self
+    struct variable *path = (struct variable*)(struct variable*)stack_pop(context->rhs);
+    remove(byte_array_to_string(path->str));
+}
+
+struct string_func builtin_funcs[] = {
+	{"yield", (bridge*)&sys_callback2c},
+    {"print", (bridge*)&sys_print},
+    {"save", (bridge*)&sys_save},
+    {"load", (bridge*)(bridge*)&sys_load},
+    {"remove", (bridge*)&sys_rm},
+};
+
+struct variable *func_map(struct Context *context)
+{
+    struct map *map = map_new();
+    for (int i=0; i<ARRAY_LEN(builtin_funcs); i++) {
+        struct byte_array *name = byte_array_from_string(builtin_funcs[i].name);
+        struct variable *value = variable_new_c(context, builtin_funcs[i].func);
+        map_insert(map, name, value);
+    }
+    return variable_new_map(context, map);
+}
+
+// built-in member functions
+
+#define FNC_STRING      "string"
+#define FNC_LIST        "list"
+#define FNC_TYPE        "type"
+#define FNC_LENGTH      "length"
+#define FNC_KEYS        "keys"
+#define FNC_VALUES      "values"
+#define FNC_SERIALIZE   "serialize"
+#define FNC_DESERIALIZE "deserialize"
+#define FNC_SORT        "sort"
+#define FNC_FIND        "find"
+#define FNC_REPLACE     "replace"
+#define FNC_PART        "part"
+#define FNC_REMOVE        "remove"
+#define FNC_INSERT        "insert"
+
+struct variable *comparator = NULL;
+
+int (compar)(struct Context *context, const void *a, const void *b)
+{
+    struct variable *av = *(struct variable**)a;
+    struct variable *bv = *(struct variable**)b;
+
+    if (comparator) {
+
+        assert_message(comparator->type == VAR_FNC, "non-function comparator");
+        stack_push(context->rhs, av);
+        stack_push(context->rhs, bv);
+        byte_array_reset(comparator->str);
+        stack_push(context->operand_stack, comparator);
+        vm_call(context);
+
+        struct variable *result = (struct variable*)stack_pop(context->rhs);
+        assert_message(result->type == VAR_INT, "non-integer comparison result");
+        return result->integer;
+
+    } else {
+
+        enum VarType at = av->type;
+        enum VarType bt = bv->type;
+
+        if (at == VAR_INT && bt == VAR_INT) {
+            // DEBUGPRINT("compare %p:%d to %p:%d : %d\n", av, av->integer, bv, bv->integer, av->integer - bv->integer);
+            return av->integer - bv->integer;
+        } else
+            DEBUGPRINT("can't compare %s to %s\n", var_type_str(at), var_type_str(bt));
+
+        vm_exit_message(context, "incompatible types for comparison");
+        return 0;
+    }
+}
+
+int testarr[] = { 6, 5, 3, 1, 8, 7, 2, 4 };
+//int testarr[] = { 2,1 };
+int len = sizeof(testarr)/sizeof(testarr[0]);
+
+void heapset(size_t width, void *base0, uint32_t index0, void *base1, uint32_t index1) {
+    uint8_t *p0 = (uint8_t*)base0 + index0 * width;
+    uint8_t *p1 = (uint8_t*)base1 + index1 * width;
+    while (width--)
+        *(p0 + width) = *(p1 + width);
+}
+
+int heapcmp(struct Context *context,
+            int (*compar)(struct Context *, const void *, const void *),
+            size_t width, void *base0, uint32_t index0, void *base1, uint32_t index1) {
+    uint8_t *p0 = (uint8_t*)base0 + index0 * width;
+    uint8_t *p1 = (uint8_t*)base1 + index1 * width;
+    return compar(context, p0, p1);
+}
+
+int heapsortfg(struct Context *context,
+               void *base, size_t nel, size_t width,
+               int (*compar)(struct Context *, const void *, const void *))
+{
+    void *t = malloc(width); // the temporary value
+    unsigned int n = nel, parent = nel/2, index, child; // heap indexes
+    for (;;) { // loop until array is sorted
+        if (parent > 0) { // first stage - Sorting the heap
+            heapset(width, t, 0, base, --parent);
+        } else { // second stage - Extracting elements in-place
+            if (!--n) { // make the heap smaller
+                free(t);
+                return 0; // When the heap is empty, we are done
+            }
+            heapset(width, t, 0, base, n);
+            heapset(width, base, n, base, 0);
+        }
+        // insert operation - pushing t down the heap to replace the parent
+        index = parent; // start at the parent index
+        child = index * 2 + 1; // get its left child index
+        while (child < n) {
+            if (child + 1 < n  && // choose the largest child
+                heapcmp(context, compar, width, base, child+1, base, child) > 0) {
+                child++; // right child exists and is bigger
+            }
+            // is the largest child larger than the entry?
+            if (heapcmp(context, compar, width, base, child, t, 0) > 0) {
+                heapset(width, base, index, base, child);
+                index = child; // move index to the child
+                child = index * 2 + 1; // get the left child and go around again
+            } else
+                break; // t's place is found
+        }
+        // store the temporary value at its new location
+        heapset(width, base, index, t, 0);
+    }
+}
+
+void cfnc_sort(struct Context *context)
+{
+    struct variable *self = (struct variable*)stack_pop(context->rhs);
+    assert_message(self->type == VAR_LST, "sorting a non-list");
+    comparator = (struct variable*)stack_pop(context->rhs);
+
+    int num_items = self->list->length;
+
+    int success = heapsortfg(context, self->list->data, num_items, sizeof(struct variable*), &compar);
+    assert_message(!success, "error sorting");
+}
+
+struct variable *variable_part(struct Context *context, struct variable *self, uint32_t start, int32_t length)
+{
+    null_check(self);
+    switch (self->type) {
+        case VAR_STR: {
+            struct byte_array *str = byte_array_part(self->str, start, length);
+            return variable_new_str(context, str);
+        }
+        case VAR_LST: {
+            struct array *list = array_part(self->list, start, length);
+            return variable_new_list(context, list);
+        }
+        default:
+            return (struct variable*)exit_message("bad part type");
+    }
+}
+
+void variable_remove(struct variable *self, uint32_t start, int32_t length)
+{
+    null_check(self);
+    switch (self->type) {
+        case VAR_STR:
+            byte_array_remove(self->str, start, length);
+            break;
+        case VAR_LST:
+            array_remove(self->list, start, length);
+            break;
+        default:
+            exit_message("bad remove type");
+    }
+}
+
+struct variable *variable_concatenate(struct Context *context, int n, const struct variable* v, ...)
+{
+    struct variable* result = variable_copy(context, v);
+
+    va_list argp;
+    for(va_start(argp, v); --n;) {
+        struct variable* parameter = va_arg(argp, struct variable* );
+        if (!parameter)
+            continue;
+        else if (!result)
+            result = variable_copy(context, parameter);
+        else switch (result->type) {
+            case VAR_STR: byte_array_append(result->str, parameter->str); break;
+            case VAR_LST: array_append(result->list, parameter->list);    break;
+            default: return (struct variable*)exit_message("bad concat type");
+        }
+    }
+
+    va_end(argp);
+    return result;
+}
+
+void cfnc_chop(struct Context *context, bool part)
+{
+    struct variable *self = (struct variable*)stack_pop(context->rhs);
+    struct variable *start = (struct variable*)stack_pop(context->rhs);
+    struct variable *length = (struct variable*)stack_pop(context->rhs);
+    assert_message(start->type == VAR_INT, "non-integer index");
+    assert_message(length->type == VAR_INT, "non-integer length");
+    int32_t beginning = start->integer;
+    int32_t foraslongas = length->integer;
+
+    struct variable *result = variable_copy(context, self);
+    if (part)
+        result = variable_part(context, result, beginning, foraslongas);
+    else
+        variable_remove(result, beginning, foraslongas);
+    stack_push(context->operand_stack, result);
+}
+
+static inline void cfnc_part(struct Context *context) {
+    cfnc_chop(context, true);
+}
+
+static inline void cfnc_remove(struct Context *context) {
+    cfnc_chop(context, false);
+}
+
+void cfnc_find(struct Context *context)
+{
+    struct variable *self = (struct variable*)stack_pop(context->rhs);
+    struct variable *sought = (struct variable*)stack_pop(context->rhs);
+    struct variable *start = (struct variable*)stack_pop(context->rhs);
+
+    null_check(self);
+    null_check(sought);
+    assert_message(self->type == VAR_STR, "searching in a non-list");
+    assert_message(sought->type == VAR_STR, "searching for a non-list");
+    if (start) assert_message(start->type == VAR_INT, "non-integer index");
+
+    int32_t beginning = start ? start->integer : 0;
+    int32_t index = byte_array_find(self->str, sought->str, beginning);
+    struct variable *result = variable_new_int(context, index);
+    stack_push(context->operand_stack, result);
+}
+
+void cfnc_insert(struct Context *context)
+{
+    struct variable *self = (struct variable*)stack_pop(context->rhs);
+    struct variable *start = (struct variable*)stack_pop(context->rhs);
+    struct variable *insertion = (struct variable*)stack_pop(context->rhs);
+    assert_message(start->type == VAR_INT, "non-integer index");
+    assert_message(insertion && insertion->type == self->type, "insertion doesn't match destination");
+
+    int32_t position = start->integer;
+    struct variable *first = variable_part(context, variable_copy(context, self), 0, position);
+    struct variable *second = variable_part(context, variable_copy(context, self), position, -1);
+    struct variable *joined = variable_concatenate(context, 3, first, self, second);
+    stack_push(context->operand_stack, joined);
+}
+
+//    a                b        c
+// <sought> <replacement> [<start>]
+// <start> <length> <replacement>
+void replace(struct Context *context)
+{
+    struct variable *self = (struct variable*)stack_pop(context->rhs);
+    struct variable *a = (struct variable*)stack_pop(context->rhs);
+    struct variable *b = (struct variable*)stack_pop(context->rhs);
+    struct variable *c = (struct variable*)stack_pop(context->rhs);
+    
+    null_check(self);
+    null_check(b);
+    assert_message(self->type == VAR_STR, "searching in a non-string");
+    
+    int32_t where = 0;
+    struct byte_array *replaced = self->str;
+    
+    if (a->type == VAR_STR) { // find a, replace with b
+        
+        assert_message(b->type == VAR_STR, "non-string replacement");
+        
+        if (c) { // replace first match after index b
+            
+            assert_message(c->type == VAR_INT, "non-integer index");
+            uint32_t found = byte_array_find(self->str, a->str, c->integer);
+            replaced = byte_array_replace(self->str, b->str, found, b->str->length);
+            
+        } else for(;;) { // replace all
+            
+            if ((where = byte_array_find(self->str, a->str, where)) < 0)
+                break;
+            replaced = byte_array_replace(replaced, b->str, where++, a->str->length);            
+        }
+        
+    } else if (a->type == VAR_INT ) { // replace at index a, length b, insert c
+        
+        assert_message(a || a->type == VAR_INT, "non-integer count");
+        assert_message(b || b->type == VAR_INT, "non-integer start");
+        replaced = byte_array_replace(self->str, c->str, a->integer, b->integer);
+        
+    } else exit_message("replacement is not a string");
+    
+    null_check(replaced);
+    struct variable *result = variable_new_str(context, replaced);
+    stack_push(context->operand_stack, result);
+}
+
+
+struct variable *builtin_method(struct Context *context, 
+                                struct variable *indexable,
+                                const struct variable *index)
+{
+    enum VarType it = indexable->type;
+    const char *idxstr = byte_array_to_string(index->str);
+
+    if (!strcmp(idxstr, FNC_LENGTH))
+        return variable_new_int(context, indexable->list->length);
+    if (!strcmp(idxstr, FNC_TYPE)) {
+        const char *typestr = var_type_str(it);
+        return variable_new_str(context, byte_array_from_string(typestr));
+    }
+
+    if (!strcmp(idxstr, FNC_STRING))
+        return variable_new_str(context, variable_value(context, indexable));
+
+    if (!strcmp(idxstr, FNC_LIST))
+        return variable_new_list(context, indexable->list);
+
+    if (!strcmp(idxstr, FNC_KEYS)) {
+        assert_message(it == VAR_LST || it == VAR_MAP, "keys are only for map or list");
+
+        struct variable *v = variable_new_list(context, array_new());
+        if (indexable->map) {
+            const struct array *a = map_keys(indexable->map);
+            for (int i=0; i<a->length; i++) {
+                struct variable *u = variable_new_str(context, (struct byte_array*)array_get(a, i));
+                array_add(v->list, u);
+            }
+        }
+        return v;
+    }
+
+    if (!strcmp(idxstr, FNC_VALUES)) {
+        assert_message(it == VAR_LST || it == VAR_MAP, "values are only for map or list");
+        if (!indexable->map)
+            return variable_new_list(context, array_new());
+        else
+            return variable_new_list(context, (struct array*)map_values(indexable->map));
+    }
+
+    if (!strcmp(idxstr, FNC_SERIALIZE)) {
+        struct byte_array *bits = variable_serialize(context, 0, indexable);
+        return variable_new_str(context, bits);
+    }
+
+    if (!strcmp(idxstr, FNC_DESERIALIZE)) {
+        struct byte_array *bits = indexable->str;
+        byte_array_reset(bits);
+        struct variable *d = variable_deserialize(context, bits);
+        return d;
+    }
+
+    if (!strcmp(idxstr, FNC_SORT)) {
+        assert_message(indexable->type == VAR_LST, "sorting non-list");
+        return variable_new_c(context, &cfnc_sort);
+    }
+
+    if (!strcmp(idxstr, FNC_FIND)) {
+        assert_message(indexable->type == VAR_STR, "searching in non-string");
+        return variable_new_c(context, &cfnc_find);
+    }
+
+    if (!strcmp(idxstr, FNC_PART))
+        return variable_new_c(context, &cfnc_part);
+
+    if (!strcmp(idxstr, FNC_REMOVE))
+        return variable_new_c(context, &cfnc_remove);
+
+    if (!strcmp(idxstr, FNC_INSERT))
+        return variable_new_c(context, &cfnc_insert);
+
+    if (!strcmp(idxstr, FNC_REPLACE))
+        return variable_new_c(context, &replace);
+
+    return NULL;
+}